2012-04-24 117 views
4

我已经写了使用资源库使用RavenDB提到在以下博客-后 (http://www.codecapers.com/post/Using-RavenDB-with-ASPNET-MVC.aspx)以下方法:IRepository如何进行单元测试?

public User GetUserById(string id) 
{ 
    var user = (from usr in _repository.All<User>() where usr.Id == id select usr).FirstOrDefault(); 

    if (user == null) 
    { 
      throw new NullReferenceException("No user with the id (" + id + ") could be found."); 
    } 

    return user; 
} 

你将如何单元测试这种方法与NUnit的(也许MOQ)?

“用户”只是一个普通的类。

回答

0

的第一个问题将是 - 什么是你在这方面的测试?提供的方法确实只有两个结果,所以基本上测试user是否为空。这是一个增值测试吗?

至于如何,林假设_repository通过某种机制注入?如果是这样,那么只需提供一个Mock<IRepository>(根据需要插入您的类型名称),然后在注入的地方注入_repository。然后,您可以设置返回值并测试您的方法是否存在异常。

mockRepository.Setup(x => x.All<User>()).Returns(new List<User> { ... }); 
+1

否:您还在测试您的方法是否会返回正确的用户。没有什么可以保证'GetUserById(“4”)'返回一个ID为“4”的用户,除非你明确地测试它。假设我只从库中返回数据,假设有10个'Users'的存储库,那么有11个可能的结果*。所以,如果你正在进行彻底的测试,还有很多东西需要测试。 – 2012-04-24 14:58:44

2

Usualy你不直接对存储库层写测试。 说例如你正在使用nHibernate或实体框架,而不是对知识库进行测试,从技术上讲,测试该框架。

创作者或那些ORMs已经完成了。

与数据库交谈也会让您的测试成为集成测试而不是单元测试。

单元测试将是例如对业务层嘲讽出库层。

如果你想要写一个集成测试还编写针对业务层,但不嘲笑库层,让它通过。

+0

这不是关于测试存储库层。它正在测试GetUserById方法的逻辑是正确的,它可能不是。您可以信任正确的仓库实施,但这并不意味着您的代码使用正确! – 2012-04-24 14:54:53

+0

我只提到它,道歉,如果这使我的答案不清楚。我假设GetUserById是业务层中的一种方法,因此如果您想检查方法返回的是正确的数据,则可以针对它编写集成测试。在您的测试中,您首先将测试数据插入数据库,然后执行您的方法,然后声明期望值由调用返回。如果你编写一个单元测试,你只需简单地模拟库层,并在模拟对象中设置GetUserById的期望值,以确保它被调用。 – Nope 2012-04-24 15:20:20

1

我会做以下准备代码:

  1. 确保您_repository被传递通过构造函数或属性,以便它可以很容易地改变了测试。
  2. 确保您_repository变量声明为IRepository类型,而不是具体类型。

然后,在你的测试:

  1. 创建界面的模拟,并通过这是你的_repository
  2. 重写.All<User>()方法返回的User一个已知的,硬编码列表与你的测试合适的值。
  3. 断言在一次测试中查询现有ID时返回正确的值。
  4. 断言在单独的测试中,当您查询不存在的ID时引发异常。
0

RavenDB是专门设计,让你需要模拟家居单元测试。

只需在内存中运行它,然后就可以直接对它执行单元测试。有关更多信息,请参阅this blog post

它可以让你写这样的代码:

[Fact] 
public void CanQueryForDistinctItemsUsingLinq() 
{ 
    using (var store = NewDocumentStore()) 
    { 
     using (var s = store.OpenSession()) 
     { 
      s.Store(new { Name = "ayende" }); 
      s.Store(new { Name = "ayende" }); 
      s.Store(new { Name = "rahien" }); 
      s.SaveChanges(); 
     } 

     store.DocumentDatabase.PutIndex("test", new IndexDefinition 
     { 
      Map = "from doc in docs select new { doc.Name }", 
      Stores = { { "Name", FieldStorage.Yes } } 
     }); 

     using (var s = store.OpenSession()) 
     { 
      var objects = s.Query<User>("test") 
       .Customize(x => x.WaitForNonStaleResults()) 
       .Select(o => new {o.Name }) 
       .Distinct() 
       .ToList(); 

      Assert.Equal(2, objects.Count); 
      Assert.Equal("ayende", objects[0].Name); 
      Assert.Equal("rahien", objects[1].Name); 
     } 
    } 
} 

这个来自RavenDB unit/integration tests,所以你需要一些infasctucture得到它的工作,但它给人的总体思路。

+0

是的,但是当你可以写一个实际测试整个事物(控制器,数据库等)的集成测试时,为什么还要设置模拟,期望等来编写单元测试呢? – 2012-04-24 20:20:47

+0

不确定在内存中是否意味着raven只是在内存中运行一个虚假的数据库。单元测试应该模拟所有的外部层,但是当你将数据写入数据库,内存或其他数据存储时,我会认为这不是单元测试,而是集成测试。 – Nope 2012-04-24 20:21:38

+0

@FrançoisWahl看看Ayende的一些博客文章,可以给出比我更好的解释。请参阅http://ayende.com/blog/153029/northwind-starter-kit-review-data-access-and-the-essence-of-needless-work-part-ii?key=01a97aa23ec049839c3fb2dd91421e61和http:// ayende对于初学者来说,他们是值得的生活(这个系列还有其他人) – 2012-04-24 20:24:56