2017-02-13 106 views
0

单元测试开始,我不知道如何测试我们的老代码,这看起来就像这样:单元测试方法具有依赖性(无接口)

public Player DetermineWinner(Player a, Player b) 
{ 
    if(a.Age>b.Age) 
    .... 
    ///few more conditions checking properties of both players 
} 

class Player 
{ 
    public Player (DBConnection c, world w, DateTime logTime) 
    {} //not easy to mock... 
} 

如何嘲笑呢?我明白,如果Player实现了一个接口,我可以简单地创建一个模拟并将其传递到具有期望值的单元测试中,但这不是这种情况。 Player类使用各种参数实例化,所以我不能在单元测试期间简单地创建一个实例并传递它 - 它取决于各种外部对象。 我需要模拟Player对象并同时设置它的属性,以便测试是确定性的。开始的最佳方法是什么?

下次我应该使用接口来解耦吗?

+1

把类的所有依赖'Player'它使用了一些的外部资源('DbConnection'至少)背后的接口或使他们的方法是虚拟的。然后你可以用“模拟”依赖关系来测试'Player'类。其他方法使用一些“没有限制”的嘲笑框架,它会为你做 – Fabio

+0

这里的*真实*问题不是“如何嘲笑”,而是被测试代码的非常糟糕的设计。具体而言,'Player'类不应该依赖'DBConnection'。相反,它的构造函数只应该获取真正属于某个玩家的数据项,以及在其他地方读取/写入玩家数据的数据库访问权限。 –

+0

什么是您的Visual Studio版本? – zaitsman

回答

0

我想你不明白嘲笑的真正含义。

A 嘲笑对象有没有与该类的“真正”实现。它只是“看起来”像那个班的一个对象。

但是你(或嘲笑框架)在控制该对象的行为。那么,除非该字段是私人(请参阅here)。所以:当你的播放器字段不是私人的,你没有问题。

没有模拟框架 - 你真的不能做太多。如果有的话,你可以嘲讽作为参数的所有对象被测试的类的构造函数。

换句话说:最后,你需要一些类“X”的对象“x”;当使用“真实”类“X”给你带来很多麻烦时,你必须用看起来像“X”的东西来代替它。

最坏的情况下,你可能有两个不同版本的X类;但那会让事情变得非常复杂。

+0

是的,它看起来像一个,但是如何在单元测试期间创建它(假设没有框架可用)?我会很感激例如使用我的代码片段。 – user970696

+0

为你提供一些更新,但我担心没有太多可以帮助你。当你不能修改源代码,并且你不能使用模拟框架时,那么你的内容有点破裂。 – GhostCat

1

你可以通过使用像Typemock这样的框架来单元测试你的代码而不用改变它,它可以让你嘲笑具体的依赖关系而不需要添加接口,当你选择一个类来模拟(在这种情况下,“Player” typemock也会自动模拟其中的所有依赖关系)。

在你给出的例子:

public class UnitTest1 
    { 
     [TestMethod] 
     public void TestDetermineWinner_B_IsTheWinner() 
     { 
      var P1 = Isolate.Fake.Instance<Player>(); 
      var P2 = Isolate.Fake.Instance<Player>(); 

      Isolate.WhenCalled(() => P1.Age).WillReturn(0); 
      Isolate.WhenCalled(() => P2.Age).WillReturn(1); 

      var result = new ClassUnderTest().DetermineWinner(P1, P2); 

      Assert.AreEqual(P2, result); 
     } 
    } 
    public class ClassUnderTest 
    { 
     public Player DetermineWinner(Player a, Player b) 
     { 
      if (a.Age > b.Age) { return a; } 
      return b; 
     ///few more conditions checking properties of both players 
     } 
    } 
    public class Player 
    { 
     public Player(DbConnection c, world w, DateTime logTime) 
     { } //not easy to mock... 

     public int Age { get; internal set; } 
    } 
+0

你有点忘了提及,你必须支付Typemock :) – zaitsman

+0

但为什么它需要支付一些问题,让你的生活更轻松? – JamesR

+0

由于购买VS企业更加谨慎 - >您可以获得相同的功能,加上其他功能(如历史调试,ADO.net跟踪等) – zaitsman

相关问题