2013-10-30 24 views
2

所以我为我的单元测试玩弄嘲讽框架(Moq),并想知道什么时候应该使用模拟框架?何时使用Mocking Framework?

什么是以下两个试验之间的利益/缺点:

public class Tests 
{ 
    [Fact] 
    public void TestWithMock() 
    { 
     // Arrange 
     var repo = new Mock<IRepository>(); 

     var p = new Mock<Person>(); 
     p.Setup(x => x.Id).Returns(1); 
     p.Setup(x => x.Name).Returns("Joe Blow"); 
     p.Setup(x => x.AkaNames).Returns(new List<string> { "Joey", "Mugs" }); 
     p.Setup(x => x.AkaNames.Remove(It.IsAny<string>())); 

     // Act 
     var service = new Service(repo.Object); 
     service.RemoveAkaName(p.Object, "Mugs"); 

     // Assert 
     p.Verify(x => x.AkaNames.Remove("Mugs"), Times.Once()); 
    } 

    [Fact] 
    public void TestWithoutMock() 
    { 
     // Arrange 
     var repo = new Mock<IRepository>(); 

     var p = new Person { Id = 1, Name = "Joe Blow", AkaNames = new List<string> { "Joey", "Mugs" } }; 

     // Act 
     var service = new Service(repo.Object); 
     service.RemoveAkaName(p, "Mugs"); 

     // Assert 
     Assert.True(p.AkaNames.Count == 1); 
     Assert.True(p.AkaNames[0] == "Joey"); 
    } 
} 
+3

模拟允许您控制所有未测试的变量,以便您只测试一段代码。 – paqogomez

+2

+1 paqogomez,换句话说,模拟允许你隔离被测代码,这样你只能测试一个特定的代码段。好处是红色或绿色的测试结果表明哪部分代码是错误的。你通常嘲笑服务,但往往更多。然而,在这里,人们几乎不需要被嘲笑。 – citykid

回答

1

的模拟框架被用来去除的依赖性,所以单元测试将集中在“单位”进行测试。在你的情况下,这个人看起来像一个简单的实体类,没有必要为它使用Mocking。

1

嘲笑有许多好处,尤其是在敏捷编程中,许多快速发布周期意味着系统结构和实际数据可能不完整。在这种情况下,您可以模拟库来模拟生产代码,以便继续使用ui或服务。这通常与Ninject之类的IoC机制相辅相成,以简化切换到真实存储库的过程。你给出的两个例子是平等的,没有任何其他的背景,我会说这是他们之间的选择问题。 moq中流利的api可能更容易被理解为自我记录。这是我的意见,虽然;)

1

模拟是用来测试对象,不能孤立地运作。假设函数A依赖于函数B,对函数A执行单元测试,我们甚至结束了测试函数B.通过使用模拟,可以模拟函数B的功能,并且测试可以仅集中于函数A上。

7

使用模拟对象到确实创建一个单元测试 - 一个测试,其中所有的依赖关系被假定为正确运行,并且你想知道的只是如果SUT(系统在测试 - 一种说你正在测试的类的奇特方式)作品。

模拟对象有助于“保证”您的依赖关系正常工作,因为您创建了这些依赖关系的模拟版本,从而生成您配置的结果。如果你正在测试的一个类在其他所有“正在工作”的情况下运行,那么问题就变成了。

当您测试缓慢依赖的对象时(如数据库或Web服务),模拟对象尤为重要。如果您真的需要访问数据库或进行真正的Web服务调用,您的测试将需要更多时间来运行。如果只有几秒钟的时间,这是可以忍受的,但是当您在服务器上运行数百个测试时,这会加快实现速度并削弱您的自动化。

这就是真正使模拟对象变得重要的原因 - 减少构建 - 测试 - 部署周期时间。确保您的测试快速运行对于有效的软件开发至关重要。

1

模拟框架可用于模拟测试代码中的集成点。我认为你的具体例子不适用于模拟框架,因为你已经可以直接在代码中注入依赖关系(Person)了。在这种情况下使用模拟框架实际上使其复杂化。

更好的用例是如果你有一个库调用数据库。从单元测试的角度来看,模拟db调用并返回预定的数据是可取的。这样做的主要优点是消除了对数据的依赖性,而且性能也很好,因为数据库调用会降低测试速度。

2

我使用写单元测试有一些规则。

  1. 如果我的被测系统(SUT)或被测物具有依赖性 然后我嘲笑他们。
  2. 如果我测试一个返回结果的方法,那么我只有 检查结果。如果依赖关系作为方法的参数传递,它们应该被模拟。 (见1)
  3. 如果我测试'void'方法,那么验证mocks是测试的最佳选择。

有一篇Martin Fowler的旧文章Mocks Aren't Stubs

在第一次测试中,您使用模拟,并在第二个测试中使用存根。

另外我看到一些导致您的问题的设计问题。

如果允许从AkaNames集合中删除AkaName那么可以使用存根并检查该人的状态。如果您将具体方法void RemoveAkaName(string name)添加到Person类中,则应使用mock来验证其调用。 RemoveAkaName的逻辑应作为Person类测试的一部分进行测试。

我会使用存根product和模拟为repository为您的代码。