【问题标题】:How can I Fake Base Class method using FakeItEasy如何使用 FakeItEasy 伪造基类方法
【发布时间】:2015-02-20 19:16:31
【问题描述】:

我正在尝试使用 FakeItEasy。我有一个特定的场景,要么无法理解如何测试,要么无法使用 FakeItEasy

假设我有一个看起来像这样的基类和派生类

public class BaseClass {
     protected bool BaseClassMethod() { return true; }
   }

public class DerivedClass : BaseClass {
     public void DoSomething(){
        if(BaseClassMethod()) Console.WriteLine("Bla");
        else Console.WriteLine("Worked");
  }
}

现在我希望能够测试 DerivedClass,但能够伪造 BaseClassMethod()。我尝试做类似的事情

var fakeBaseClass = A.Fake<BaseClass>();
A.CallTo(fakedBaseClass).Where(x => x.Method.Name   "BaseClassMethod")).WithReturnType<bool>(). Returns(false); 
var derivedClass = new DerivedClass(); // Am hoping that the DerivedClass will use the Faked Baseclass that I have created above.
derivedClass.DoSomething()

这不符合我的预期。我在这里遗漏了什么,还是 FakeItEasy 无法做到这一点?

谢谢 卡提克

【问题讨论】:

    标签: mocking fakeiteasy


    【解决方案1】:

    您的方法存在一些问题。

    第一个问题是您创建的fakeBaseClassderivedClass 之间没有任何联系,因此它们无法相互影响。为了完成我认为你正在尝试做的事情,你真的想制作一个假的 DerivedClass 并操纵它的行为(实际上,一般来说,这种类型的测试是有争议的,但让我们专注于机制并搁置它是否是现在是个好主意)。

    通过伪装DerivedClass,FakeItEasy 实际上将实例化一种新类型的类,该类派生自DerivedClass,因此将调用并访问@987654329 的所有(受保护或公共)方法@ 和 BaseClass。然后你可以从BaseClassMethod 设置你想要的行为并锻炼DoSomething 并希望得到你想要的结果。

    当我们尝试这个时会导致问题的第二件事是BaseClassMethod 不是虚拟的。 FakeItEasy(及其同类隔离框架)不能伪造任何非虚拟的方法。你可以在What can be faked了解更多关于什么是可伪造的。

    因此,将这两个更改放在一起,我得到如下代码:

    public class BaseClass
    {
        protected virtual bool BaseClassMethod()
        {
            return true;
        }
    }
    
    public class DerivedClass : BaseClass
    {
        public string DoSomething()
        {
            if (BaseClassMethod())
            {
                return ("Bla");
            }
            else
            {
                return ("Worked");
            }
        }
    }
    
    [Test]
    public void MethodName_StateUnderTest_ExpectedBehavior()
    {
        var fakedDerivedClass = A.Fake<DerivedClass>();
        A.CallTo(fakedDerivedClass)
            .Where(x => x.Method.Name == "BaseClassMethod")
            .WithReturnType<bool>()
            .Returns(false);
    
        Assert.That(fakedDerivedClass.DoSomething(), Is.EqualTo("Worked"));
    }
    

    此测试通过。请注意,我已对您的原件进行了更改(除了更正拼写错误):

    1. BaseClassMethod 现在是虚拟的
    2. 我正在创建一个假的 DerivedClass 用于测试,并且
    3. DoSomething 返回一个字符串,而不是写入控制台。这不是绝对必要的,但让我的测试更容易编写。

    请注意,如果BaseClassMethod 不是虚拟的,那么它不可能返回除true 之外的任何内容,而且我认为编写测试以查看DoSomething 获得false 来自它。

    有关为什么伪造被测类(而不是该类的合作者)可能是一个坏主意的更多讨论,请参阅Use FakeItEasy's A.CallTo() on another method in same object 上的 cmets 和我对Using FakeItEasy, is it possible to create a dummy object of a type that takes generic type parameters 的回答。

    但是你对这种方法的感受是你必须自己接受的。

    【讨论】:

    • 感谢您的评论。你的回答很中肯,写得很好