关于单元测试:使用FakeItEasy模拟私有方法

Mock private methods using FakeItEasy

我已经实现了使用FakeItEasy Framework模拟测试公共虚拟方法的解决方案。 下面我有一个带有Private方法的Test类,而private方法不能是虚方法。 所以请帮我模拟使用FakeItEasy Framework的Private方法

课程待测

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class XYZ
{
    public static int nValue = 0;

    private  void AddInetegers()
    {
        int i = 3;

        int j = i * 100;
        int k = j * 30 / 100;

        Show(String.Format("Value Here {0}", k.ToString()));

        nValue = k;
    }

    public virtual void Show(string message)
    {
        MessageBox.Show(message);
    }
}

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[TestMethod]
   public void Test_Using_FakeItEasy()
    {

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

        A.CallTo(() => instance.Show("Hello"));

        //A.CallTo(() => instance.AddInetegers(3)).CallsBaseMethod();

        A.CallTo(instance).Where(x => x.Method.Name.Contains("AddInetegers")).MustHaveHappened();


        Assert.AreEqual(90, XYZ.nValue);
    }

错误:

Result Message: Test method PrjMSTest.Test.Test_Using_FakeItEasy
threw exception: FakeItEasy.ExpectationException:

Assertion failed for the following call:
Any call made to the fake object.
where x => x.Method.Name.Contains("AddInetegers")
Expected to find it at least once but no calls were made to the fake object.


正如他们在评论中告诉你的那样,你不能轻易地测试私有方法,在绝大多数情况下,你可能不应该这样做。
如果由于某种原因,你仍然想要测试AddInetegers(),那么有一种"脏"的方法可以保留某种信息并测试你的方法。

首先,你必须使AddInetegers内部;它不会在你的装配外可见,你将能够测试它。

然后找到XYZ类所属的项目的Properties AssemblyInfo.cs文件;假设您的项目名为MyProject且测试项目为MyProjectTests,则可以添加

1
using System.Runtime.CompilerServices;

到AssemblyInfo.cs和。的顶部

1
[assembly: InternalsVisibleTo("MyProjectTests")]

至底部。这将使您的方法可测试。更多信息在这里或这里。

然后有一个更脏的方式,即保持你的方法私密;它被提及,例如这里或这里依赖PrivateObject,这是自2004年以来詹姆斯·纽柯克本人的这篇文章

1
2
3
4
5
var CurrentInstance = new XYZ();
var PrivateObject= new PrivateObject(CurrentInstance);
PrivateObject.Invoke("AddInetegers");

Assert.AreEqual(90, XYZ.nValue);

老实说,除非你处理非常复杂的遗留代码,否则你可能想要利用你的设计技巧,想一想你为什么要测试一个私有方法,以及为什么它的作者决定将它私有化。
这个答案是非常彻底的,为什么你不应该测试私有方法和/或为什么你想要测试的方法不应该是私有的。
但它也解释了为什么你可能需要这样做:

  • 在对遗留系统进行重构和/或添加测试时,您可能仍然没有时间熟悉它
  • sometimes it is simply safest to just test the private functionality

  • 有人给你一个不合理的截止日期
  • You're in a rush, and have to do the fastest thing possible for here
    and now. In the long run, you don't want to test private methods. But
    I will say that it usually takes some time to refactor to address
    design issues. And sometimes you have to ship in a week. That's okay:
    do the quick and dirty and test the private methods using a groping
    tool if that's what you think is the fastest and most reliable way to
    get the job done. But understand that what you did was suboptimal in
    the long run, and please consider coming back to it (or, if it was
    forgotten about but you see it later, fix it).