如何在C#中模拟PrivateObject

时间:2017-03-13 07:07:23

标签: c# unit-testing mocking moq privateobject.invoke

我有这段代码:

    [TestMethod]
    public void TestMethod()
    {
        TextBox txtBox= new TextBox() { Text = "Test" };

        PrivateObject privateObj= new PrivateObject(someObject);
        var mockObj = new Mock<PrivateObject>();
        mockObj.Setup(x => x.Invoke("SomeMethod", It.IsAny<string>())).Returns(true);

        object result = privateObj.Invoke("DoSomething", txtBox, EventArgs.Empty);

        Assert.AreEqual(txtBox.Text, string.Empty);
    }

方法&#34; DoSomething&#34;电话&#34; SomeMethod&#34;方法,返回布尔类型。我怎么能模拟SometMetod,所以当我打电话给他时,他会回复我需要的东西?

1 个答案:

答案 0 :(得分:1)

抱歉,我应该更彻底地调查你的问题。我没有意识到PrivateObject是已经存在的.NET框架类。

我的答案不是直接回答你的问题,而是我将它留在这里无论如何。我假设您使用Moq,因此以下部分类不可用于模拟:

  • 非虚拟会员
  • 静态成员
  • 扩展方法
  • 密封班的任何成员
  • 字段

私人会员可以接受测试,我并不是说它一般都是错误的。但是,通常需要测试私有成员是代码设计错误的标志。

私人方法和字段是实施细节,不应影响您的课程。功能。不要将每种方法都视为一个单元,而应将该类视为一个单元。测试你的课程&#39; 行为并且它会做它应该做的事情并且不测试 它是如何做的。

object result = privateObj.Invoke(&#34; DoSomething&#34;,txtBox,EventArgs.Empty); 您正在DoSomething上调用privateObj方法,而不是{em>未设置的mockObj,以返回您需要的内容&#34;。

您的单元测试应该达到什么程度? 您的被测系统的模拟行为是一种矛盾,因为测试结果不能代表系统的实际行为。

我想您可以做的是将SomeMethod的{​​{1}}功能从PrivateObject中提取出来依赖它,让我们说IHaveSomeMethod

public interface IHaveSomeMethod {
    bool SomeMethod();
}

public class PrivateObject {
    private IHaveSomeMethod dependency;

    public PrivateObject(???SomeObject someObject???, IHaveSomeMethod ihsm) {
        // ...
        this.iHaveSomeMethod = ihsm;
        // ...
    }

    public void DoSometing() {
        // ...
        iHaveSomeMethod.SomeMethod();
        // ...
    }
}

然后你可以像这样测试

[TestMethod]
public void TestMethod()
{
    TextBox txtBox= new TextBox() { Text = "Test" };

    var mockObj = new Mock<IHaveSomeMethod>();
    mockObj.Setup(x => x.Invoke("SomeMethod", It.IsAny<string>())).Returns(true);

    var sut = new PrivateObject(???someObject???, mockObj.Object); // system under test
    object result = sut.Invoke("DoSomething", txtBox, EventArgs.Empty);

    Assert.AreEqual(txtBox.Text, string.Empty);
}