IRepository如何进行单元测试?
我已经写了使用资源库使用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)?
“用户”只是一个普通的类。
的第一个问题将是 - 什么是你在这方面的测试?提供的方法确实只有两个结果,所以基本上测试user
是否为空。这是一个增值测试吗?
至于如何,林假设_repository
通过某种机制注入?如果是这样,那么只需提供一个Mock<IRepository>
(根据需要插入您的类型名称),然后在注入的地方注入_repository
。然后,您可以设置返回值并测试您的方法是否存在异常。
mockRepository.Setup(x => x.All<User>()).Returns(new List<User> { ... });
Usualy你不直接对存储库层写测试。 说例如你正在使用nHibernate或实体框架,而不是对知识库进行测试,从技术上讲,测试该框架。
创作者或那些ORMs已经完成了。
与数据库交谈也会让您的测试成为集成测试而不是单元测试。
单元测试将是例如对业务层嘲讽出库层。
如果你想要写一个集成测试还编写针对业务层,但不嘲笑库层,让它通过。
这不是关于测试存储库层。它正在测试GetUserById方法的逻辑是正确的,它可能不是。您可以信任正确的仓库实施,但这并不意味着您的代码使用正确! – 2012-04-24 14:54:53
我只提到它,道歉,如果这使我的答案不清楚。我假设GetUserById是业务层中的一种方法,因此如果您想检查方法返回的是正确的数据,则可以针对它编写集成测试。在您的测试中,您首先将测试数据插入数据库,然后执行您的方法,然后声明期望值由调用返回。如果你编写一个单元测试,你只需简单地模拟库层,并在模拟对象中设置GetUserById的期望值,以确保它被调用。 – Nope 2012-04-24 15:20:20
我会做以下准备代码:
- 确保您
_repository
被传递通过构造函数或属性,以便它可以很容易地改变了测试。 - 确保您
_repository
变量声明为IRepository
类型,而不是具体类型。
然后,在你的测试:
- 创建界面的模拟,并通过这是你的
_repository
。 - 重写
.All<User>()
方法返回的User
一个已知的,硬编码列表与你的测试合适的值。 - 断言在一次测试中查询现有ID时返回正确的值。
- 断言在单独的测试中,当您查询不存在的ID时引发异常。
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得到它的工作,但它给人的总体思路。
是的,但是当你可以写一个实际测试整个事物(控制器,数据库等)的集成测试时,为什么还要设置模拟,期望等来编写单元测试呢? – 2012-04-24 20:20:47
不确定在内存中是否意味着raven只是在内存中运行一个虚假的数据库。单元测试应该模拟所有的外部层,但是当你将数据写入数据库,内存或其他数据存储时,我会认为这不是单元测试,而是集成测试。 – Nope 2012-04-24 20:21:38
@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
否:您还在测试您的方法是否会返回正确的用户。没有什么可以保证'GetUserById(“4”)'返回一个ID为“4”的用户,除非你明确地测试它。假设我只从库中返回数据,假设有10个'Users'的存储库,那么有11个可能的结果*。所以,如果你正在进行彻底的测试,还有很多东西需要测试。 – 2012-04-24 14:58:44