2010-12-09 77 views
2

我使用.NET 4,NUnit和Rhino mocks。我想单元测试我的新闻库,但我不确定如何去做。我的新闻库是我最终将用来与数据库进行通信的。我想用它来测试假冒伪造数据。不确定是否有可能?这是我目前有:单元测试库需要的帮助/建议

public interface INewsRepository 
{ 
    IEnumerable<News> FindAll(); 
} 

public class NewsRepository : INewsRepository 
{ 
    private readonly INewsRepository newsRepository; 

    public NewsRepository(INewsRepository newsRepository) 
    { 
     this.newsRepository = newsRepository; 
    } 

    public IEnumerable<News> FindAll() 
    { 
     return null; 
    } 
} 

我的单元测试是这样的:

public class NewsRepositoryTest 
{ 
    private INewsRepository newsRepository; 

    [SetUp] 
    public void Init() 
    { 
     newsRepository = MockRepository.GenerateMock<NewsRepository>(); 
    } 

    [Test] 
    public void FindAll_should_return_correct_news() 
    { 
     // Arrange 
     List<News> newsList = new List<News>(); 
     newsList.Add(new News { Id = 1, Title = "Test Title 1" }); 
     newsList.Add(new News { Id = 2, Title = "Test Title 2" }); 

     newsRepository.Stub(r => r.FindAll()).Return(newsList); 

     // Act 
     var actual = newsRepository.FindAll(); 

     // Assert 
     Assert.AreEqual(2, actual.Count()); 
    } 
} 

在上面的代码,我不知道我需要模拟。上面的代码编译但在NUnit GUI中关于构造器值失败。我只能假设它与我需要提供给NewsRepository的INewsRepository参数有关。我不知道如何在测试中做到这一点。有人可以纠正我的单元测试,以便它会通过NUnit GUI?某人是否也可以提供一些关于我是否正确实施存储库的反馈?

作为一个新手嘲笑,有什么我需要验证?我什么时候需要验证?它的目的是什么?我一直在努力完成一些源代码项目,一些使用验证,一些则不使用。

如果上述测试通过,这对开发者证明了什么?另一个开发人员必须对我的存储库做些什么才能使其在NUnit GUI中失败?

对不起,所有的问题,但他们是新手问题:)

我希望soomeone能帮助我。

+0

我看到对不对? NewsRepository本身具有相同的功能? – Aliostad 2010-12-09 13:36:29

+0

@Aliostad:你是什么意思? – 2010-12-09 13:39:15

回答

5

正如史蒂文所说,你在Assert对上述代码中的Mock NewsRepository。

嘲讽的想法是隔离被测代码并且创建假货以取代他们的依赖

您使用模拟NewsRepository测试的东西,使用INewsRepository,你的情况,你提到NewsService; NewsService将使用你的模拟INewsRepository

如果您在解决方案中搜索使用INewsRepository.FindAll()的任何内容,您将创建一个模拟存储库以单独测试该代码。

如果你想测试一些调用你的服务层的东西,你将需要模拟NewsService

而且,史蒂芬的说,没有必要为NewsRepository有由国际奥委会注入其自身的副本,所以:

public class NewsRepository : INewsRepository 
{ 
    private readonly INewsRepository newsRepository; 

    public NewsRepository(INewsRepository newsRepository) 
    { 
     this.newsRepository = newsRepository; 
    } 

    public IEnumerable<News> FindAll() 
    { 
     return null; 
    } 
} 

应该变成:

public class NewsRepository : INewsRepository 
{ 
    public IEnumerable<News> FindAll() 
    { 
     return null; 
    } 
} 

一旦你有功能在您需要测试的FindAll()方法中,您可以模拟他们使用的对象

作为一个伟大的风格点Art Of Unit Testing模拟对象的初始化最好从Setup方法中排除,并在方法开始时调用的辅助方法中执行。由于安装程序的调用将不可见,并使模拟的初始化不清晰。

作为另一个风格点,从这本书中,建议的单元测试命名约定是:“MethodUnderTest_Scenario_ExpectedBehavior”。 所以,

FindAll_should_return_correct_news
可能成为,例如:
FindAll_AfterAddingTwoNewsItems_ReturnsACollectionWithCountOf2

我希望这使得该方法更清晰。

2

您的FindAll_should_return_correct_news测试方法未测试存储库,它正在测试自身。你可以看到这个当你把它简化一下它确实:

[Test] 
public void FindAll_should_return_correct_news() 
{ 
    // Arrange 
    List<News> newsList = new List<News>(); 
    newsList.Add(new News { Id = 1, Title = "Test Title 1" }); 
    newsList.Add(new News { Id = 2, Title = "Test Title 2" }); 

    // Act 
    var actual = newsList; 

    // Assert 
    Assert.AreEqual(2, actual.Count()); 
} 

正如你所看到的,有什么你基本上做的是创建一个列表,加油吧和测试,如果它实际上包含的记录数你把它放进去。

当您的存储库除了数据库交互(没有应用程序逻辑)什么也不做,没有什么可以使用单元测试进行测试。你可以通过编写集成测试来解决这个问题。你基本上可以用这样一个集成测试做什么,就是在测试数据库中插入一些记录(尽管使用真实的数据库,而不是内存数据库),然后调用真实的存储库类来查看它是否从测试中获取预期记录数据库。所有应该在事务中执行并在测试结束时回滚(这确保了这些测试值得信赖)。

当您使用允许编写LINQ查询的O/RM工具时,您也可以尝试不同的方法。您可以伪造您的LINQ提供商,如您在this article中看到的那样。