我正在研究制作一个DataContext
可以在单元测试中使用的可模拟对象。这里描述了一种方法。但是,这种方法的问题在于,对存储库的更改会立即生效——在调用Commit
(或任何其他等效于)之前。SubmitChanges
另一方面,包含正确的SubmitChanges
行为将涉及从 复制大量复杂代码DataContext
,并可能导致更多错误。
模拟内存存储库(不等待SubmitChanges
)的天真实现对于使用单元测试是否可行?这通常是如何完成的?
我正在研究制作一个DataContext
可以在单元测试中使用的可模拟对象。这里描述了一种方法。但是,这种方法的问题在于,对存储库的更改会立即生效——在调用Commit
(或任何其他等效于)之前。SubmitChanges
另一方面,包含正确的SubmitChanges
行为将涉及从 复制大量复杂代码DataContext
,并可能导致更多错误。
模拟内存存储库(不等待SubmitChanges
)的天真实现对于使用单元测试是否可行?这通常是如何完成的?
如果我的理解是正确的,那么您还没有完全确定您的 SUT(被测对象)。
如果您想测试与数据库的连接性,那么我们正在谈论集成测试,您不应该模拟您的DataContext
如果你想测试调用的逻辑DataContext
那么它是一个单元测试
无论如何,我建议您将调用包装DataContext
在存储库中,存储库将负责与数据库通信,遵循这种方法将使您更轻松
我会用一个例子来说明它,最后我会推荐几个链接来帮助你编写可测试的代码。(我总是这么说,我会再说一遍,写测试很容易,真正的努力必须放在写干净的可测试代码上)
public interface IMyRepository
{
void ChangeEmail(int employeeId, string newEmail);
}
public class MyRepository : IMyRepository
{
private MyDataContext context;
public MyRepository(MyDataContext context)
{
this.context = context;
}
public void ChangeEmail(int employeeId, string newEmail)
{
//save your email using your context
}
}
现在在您的消费者代码中,您将注入您的存储库:
public class MyCommand
{
public MyCommand(IMyRepository myRepository)
...
public void ChangeEmail(int employeeId, string newEmail)
{
//adding condition just to clarify how to test
if(this.AllowChangeEmail(employeeId))
{
this.myRepository.ChangeEmail(employeeId, newEmail);
}
else
{
throw new DomainException("this should not happen");
}
}
...
}
我们已经解耦了 的使用DataContext
,从您的域代码的角度来看,DataContext
不存在,域知道的唯一代码是IMyRepository
并且因为它是一个接口,您可以轻松更改提供者更改应用程序的行为,而无需重构您的域代码
如果你注意到我还没有谈到测试,为什么?因为就像我说的,首先要做的是编写干净的可测试代码(不要误解,应该遵循 TDD,这意味着应该先编写测试,我遵循这种方法只是为了演示)现在我们有了这段代码,让我们看看测试应用程序的逻辑IMyRepository
有多容易
public class MyFakeProvider : IMyRepository
{
public void ChangeEmail(int employeeId, string newEmail)
{
//write some assert here indicating the method was called
}
}
[Test]
public void MyTest()
{
var myMock = new MyFakeProvider();
var sut = new MyCommand(myMock);
sut.Invoking(x => x.ChangeEmail(3, "my@email.com")).ShouldNotThrow();
}
这些链接只关注一件事:编写可测试的代码:
http://misko.hevery.com/code-reviewers-guide/
http://misko.hevery.com/attachments/Guide-Writing%20Testable%20Code.pdf
http://misko.hevery.com/presentations/
http://www.youtube.com/watch?v=wEhu57pih5w&feature=player_embedded
http://www.youtube.com/watch?v=RlfLCWKxHJ0&feature=player_embedded
http://www.youtube.com/watch?v=-FRm3VPhseI&feature=player_embedded
http://www.youtube.com/watch?v=4F72VULWFvc&feature=player_embedded
被测试的类/组件是什么?如果您不直接测试存储库而只测试正在使用存储库的东西,那么模拟可以根据您的需要进行。
但是,如果您想在组件和存储库之间执行端到端集成测试,则需要另一种方法,例如。针对测试数据库运行。
我创建了一个接口来表示存储库,其中有 SubmitChanges、InsertOnSubmit 等 DataContext 实现的东西。此外,您的表的 IQueryable 属性。然后,您的 DataContext 子类可以实现此接口,您无需执行任何操作。对于您的单元测试,您可以只创建一个模拟,并模仿 IQueryables 您可以创建列表并使用 AsQueryable 方法。