无法初始化模拟类的成员

时间:2019-01-15 08:18:42

标签: c# unit-testing interface moq

我有一个包含成员的界面,如下所示:

public interface IDataLoader
{
    //other stuff
    // tools for loading the items to be processed from disk or cloud
    CustomCollection ItemsToBeProcessed {get; set;}
}

我正在为消耗那些ItemsToBeProcessed的系统其他组件做UT,我想避免加载的复杂性和依赖性。

在每个UT中,我都想用特定的硬编码数据填充ItemsToBeProcessed。然后将数据馈送到要测试的模块(处理器模块),并将输出与特定的硬编码预期数据进行比较。

我的问题是我无法初始化此ItemsToBeProcessed,但我不明白为什么。

到目前为止,这是我的UT:

[Test]
public void DataProcessor_TestData1_asExpected()
{
    Mock<IDataLoader> mokedAmplifier = new Mock<IDataLoader>(MockBehavior.Loose);
    MainController.Loader = mokedAmplifier.Object;
    if(MainController.Loader.ItemsToBeProcessed == null)
        MainController.Loader.ItemsToBeProcessed = new CustomCollection();

    // here the MainController.Loader.ItemsToBeProcessed is still null.. why???

    var TestData = LoadTestData("testData1.xml");
    var ExpectedData = LoadExpectedData("ExpectedData1.xml")

    MainConroller.Loader.ItemsToBeProcessed.AddRange(TestData);

    var ProcessingModuleBeingTested = new ProcessingModule();
    var results = ProcessingModuleBeingTested.Process(MainController.Loader.ItemsToBeProcessed);
    Asert.isEqual(ExepctedData, results);
}

我如何初始化此成员?

3 个答案:

答案 0 :(得分:3)

模拟所需的成员以在调用时返回可用的对象。

var collection = new CustomCollection();
var mokedAmplifier = new Mock<IDataLoader>(MockBehavior.Loose);

mokedAmplifier.Setup(_ => _.ItemsToBeProcessed).Returns(collection);

//...

如果您希望模拟对象记住对属性所做的更改,请使用SetupAllProperties

  

指定模拟中的所有属性都应具有“属性行为”,   这意味着设置其值将导致将其保存并稍后返回   当请求属性时。 (也称为“存根”)。默认值   每个属性的值将是由   模拟的Moq.Mock.DefaultValue属性。

var mokedAmplifier = new Mock<IDataLoader>(MockBehavior.Loose);

mokedAmplifier.SetupAllProperties(); //<--

MainController.Loader = mokedAmplifier.Object;

if(MainController.Loader.ItemsToBeProcessed == null)
    MainController.Loader.ItemsToBeProcessed = new CustomCollection();

//...

参考Moq Quickstart,以帮助您理解模拟框架。

答案 1 :(得分:2)

属性只不过是一种get方法和set方法。如果要为模拟实例分配值,则只需使用 setter 方法,该方法与getter方法无关。。因此,由thefault Mock为您创建一个类似于以下内容的类:

class TheMockClass : IDataLoader
{
    CustomCollection get_ItemsToBeProcessed { return whatever; }
    void set_ItemsToBeProcessed {  }
}

如果您为此类的实例分配某些内容,则不会发生任何事情,因为setter绝对不会做任何事情(不确定具体的内部原理,但重要的是,即使setter做了任何事情,也与它无关。在吸气剂中使用。

您看到,当被模拟时,这两种方法没有任何共同之处。因此,您必须同步进行模拟。但是,通常只需模拟 getter 即可返回您的值,因为您只是使用被模拟的值,而不是设置

mokedAmplifier.Setup(_ => _.ItemsToBeProcessed).Returns(new CustomCollection());

答案 2 :(得分:1)

您需要设置属性:

    mokedAmplifier.SetupAllProperties();
    MainController.Loader = mokedAmplifier.Object;
    if (MainController.Loader.ItemsToBeProcessed == null)
        MainController.Loader.ItemsToBeProcessed = new CustomCollection();

    var coll = new CustomCollection();
    mokedAmplifier.Setup(x => x.ItemsToBeProcessed).Returns(coll);