4

如何模拟/伪造另一个函数中调用的函数的结果?通常 Test2 将是我不喜欢获取真实数据的 DataAccess 方法。我喜欢我的 unittest 测试的是业务逻辑。

这就是我现在所拥有的,但它根本不起作用。总和始终断言为 5!

public int Test1()
{
    var value = this.Test2(); //Unittest should substitute with 5
    var businesslogic = value + 10; //The business logic

    return businesslogic;
}

public int Test2()
{
    return 10; //I try to mock this value away in the test. Don´t go here!
}

然后我有一个单元测试,我想在我的“业务逻辑”上运行。

[TestMethod()]
public void TestToTest()
{
//Arrange
var instance = A.Fake<IClassWithMethods>();

      //Make calling Test2 return 5 and not 10.
A.CallTo(() => instance.Test2()).Returns(5);

      //Call the method 
var sum = instance.Test1();

//Assert if the business logic in the method works.
Assert.AreEqual(15, sum);
}
4

2 回答 2

5

据我所知,你不能这样做。

instance不是真实类的实例,只是其接口上的模型,因此调用instance.Test1()不会调用您上面描述的代码。但是,您可以自己使用 UnitTestTest2方法。

但是,您可以做 2 个单元测试。

在第一个测试(测试方法Test2)中,您使用必要的依赖项(或者如果没有具有某些值/参数的依赖项)实例化您的类。

然后使用相同的输入参数和测试Test()方法进行第二次测试。

模型仅用于必须在接口上模拟的依赖项(在您测试的类之外实例化)。即如果你有并且ClassA依赖于接口。然后你可以模拟 B 来测试 A。ClassBClassAIClassB

于 2014-02-12T16:46:30.143 回答
4

首先,让我说,我认为Tseng 的回答中有一些奇妙的观点,尤其是关于如何

  1. 伪造接口意味着永远不能调用“内部方法”,并且
  2. 你应该伪造依赖,而不是内部。如果您可以选择进行此更改,请立即执行并停止阅读我的答案。

如果您仍在阅读,我对两件事感到困惑:

  1. 应该Test1返回businessLogic?正如它所写的那样(一旦编译错误被修复),我希望Test1在返回 5 时返回 5(而不是 15)Test2
  2. TestToTest中,当您设置Returns(5)on Test2,然后调用Test1时,由于您伪造了一个接口,我希望 sum 为 0,即 int 的默认值。我不知道你怎么会得到 5。事实上,我在这个测试中复制了这种行为:

[TestMethod]
public void TestToTestInterface()
{
    //Arrange

    var instance = A.Fake<IClassWithMethods>();

    //Make calling Test2 return 5 and not 10.
    A.CallTo(() => instance.Test2()).Returns(5);

    //Call the method 
    var sum = instance.Test1();

    //Assert if the business logic in the method works.
    Assert.AreEqual(0, sum); // because Test1 wasn't faked
}

虽然我自己并不关心这种方法,但如果您真的想在 中包含可替换代码ClassWithMethods,然后测试该Test1方法,有一种方法:

  1. 我们需要制作Test1and Test2 virtual,否则它们将无法伪造。
  2. 假的ClassWithMethods,不是IClasssWithMethods
  3. 告诉 fake 当Test1被调用时,它应该调用原始代码(这又会调用 fake Test2)。

我已经将这些更改放在一起,这个测试对我来说通过了:

public class ClassWithMethods : IClassWithMethods
{
    public virtual int Test1()
    {
        var value = this.Test2(); //Unittest should substitute with 5
        var businesslogic = value + 10; //The business logic

        return businesslogic;
    }

    public virtual int Test2()
    {
        return 10; //I try to mock this value away in the test. Don´t go here!
    }
}

[TestMethod]
public void TestToTestClass()
{
    //Arrange

    var instance = A.Fake<ClassWithMethods>();

    //Make calling Test2 return 5 and not 10.
    A.CallTo(() => instance.Test2()).Returns(5);

    // Make sure that Test1 on our fake calls the original ClassWithMethods.Test1
    A.CallTo(() => instance.Test1()).CallsBaseMethod();

    //Call the method 
    var sum = instance.Test1();

    //Assert if the business logic in the method works.
    Assert.AreEqual(15, sum);
}
于 2014-02-12T20:34:18.273 回答