具有依赖性的单元测试方法(没有接口)

时间:2017-02-13 19:34:20

标签: c# unit-testing mocking

从单元测试开始,我想知道如何测试我们的旧代码,看起来像这样:

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实现了一个接口,我可以简单地创建一个mock并在单元测试中将其传递给所需的值,但这不是这里的情况。 Player类是使用各种参数实例化的,所以我不能简单地在单元测试期间创建一个实例并传递它 - 它取决于各种外部对象。 我需要模拟Player对象并同时设置其属性,以便测试是确定性的。开始时最好的方法是什么?

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

2 个答案:

答案 0 :(得分: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; }
    }

答案 1 :(得分:0)

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

模拟对象与<#34;真实&#34;该类的实现。它只是&#34;看起来&#34;就像那个阶级的对象一样。

但是你(对于模拟框架)可以控制该对象的行为。好吧,除非该字段是私有(请参阅here)。所以:当你的玩家字段不是私密的时候,你就不会有问题。

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

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

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