2012-04-30 92 views
4

我正在研究制作一个可以在单元测试中使用的可模拟DataContext。一种方法被描述为here。但是,这种方法的问题在于,对存储库的更改立即生效 - 在调用Commit(或任何其他等效于SubmitChanges)之前。嘲笑单元测试中使用的LinqToSql存储库内存

在翻盖侧,包括正确SubmitChanges行为将涉及重复很多复杂的代码DataContext,并且将可能导致更多的错误。

模拟内存存储库(不等待SubmitChanges)使用单元测试是否可行?这通常如何完成?

+1

我认为你是在正确的轨道上。如果您想单元测试您对存储库(而不是存储库本身)所做的操作,则模拟的内存中存储库是一个很好的方法。您还可以使用模拟框架,如[Moq](http://code.google.com/p/moq/)。 –

回答

2

什么是被测试的类/组件?如果你不是直接测试版本库,而只是测试一些正在使用版本库的东西,那么模拟器就可以像你所需要的那样基本。但是,如果您想要在组件和存储库之间端到端执行集成测试,则需要使用其他方法,例如,针对测试数据库运行。

+0

所以你的建议是:使用朴素的'DataContext'进行单元测试,使用带有测试数据库的真正'DataContext'进行集成测试。听起来很合理。我会等待我的反馈,看看我正在编写单元测试时,天真的嘲笑'DataContext'是否会导致任何问题。 –

1

我创建了一个接口来表示存储库,它具有SubmitChanges,InsertOnSubmit等DataContext实现的东西。此外,您的表的IQueryable属性。你的DataContext子类可以实现这个接口,你不需要做任何事情。对于你的单元测试,你可以创建一个模拟,并模仿IQueryables你可以创建列表并使用AsQueryable方法。

4

如果我的理解是正确的,你还没有完全确定你的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存根手动澄清,但在实际的代码自动模拟对象应改为使用,使用工具,如AutoFixtureFluentAssertionsMoq

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, "[email protected]")).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