最小起订量单元测试 - Return 类型

MOQ unit test - Return type

我对 MOQ 很陌生,有一个我无法解决的问题。我正在测试以下代码(我正在测试第一个 - ValidateInputBankFile):

    #region Constructor

    private readonly IErrorRepository _errorRepository;
    private readonly IFileSystem _fileSystem;
    public IP_BankInfoDeserializer(IErrorRepository errorRepository, IFileSystem fileSystem)
    {
        _errorRepository = errorRepository;
        _fileSystem = fileSystem;
    }
    #endregion

    public IP_BankInfo ValidateInputBankFile(string sPath, App.BankType bankType)
    {
        if (!_fileSystem.FileExists((sPath)))
            return null;

        //first retrieve representative bank info
        var tmpInfo = DeserializeBankInfo(bankType);

        if (tmpInfo == null)
            return null;//Does not exist

        return tmpInfo;
    }

    public IP_BankInfo DeserializeBankInfo(App.BankType bankType)
    {
        if (!IsFileCorrect(bankType))
            return null;

        IP_BankInfo info = new IP_BankInfo();

        using (var stream = new StreamReader(Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + sFolder + Path.DirectorySeparatorChar +
                                              bankType.ToString() + ".xml"))
        {
            XmlSerializer serializer = new XmlSerializer(typeof(IP_BankInfo));
            try
            {
                info = serializer.Deserialize(stream) as IP_BankInfo;
            }
            catch (Exception ex)
            {
                info = null;
            }
        }

        return info;
    }

这是我的测试方法:

    [TestMethod]
    public void ValidateInputBank_ExistingPath_ExistingBank()
    {
        Mock<IFileSystem> fileSystem = new Mock<IFileSystem>();
        fileSystem.Setup(n => n.FileExists(null)).Returns(true);

        Mock<IP_BankInfoDeserializer> mocSerializer = new Mock<IP_BankInfoDeserializer>();
        mocSerializer.Setup(n => n.DeserializeBankInfo(App.BankType.UniCredit)).Returns(new Models.IP_BankInfo());

        var result = mocSerializer.Object.ValidateInputBankFile(null, App.BankType.UniCredit);

        //Assert.AreEqual(serializer.Object.ValidateInputBankFile(null, App.BankType.UniCredit), new Models.IP_BankInfo());
    }

我想做的是避免调用 DeserializeBankInfo、return new IP_BankInfo 这样我就可以在我的 final 下检查它断言阶段。

问题是我的 var 结果 总是 return 为空。我不明白我做错了什么?

在下面的代码 mocSerializer.Setup(n => n.DeserializeBankInfo(App.BankType.UniCredit)).Returns(()=>null); 上它也失败了,但我传递了正确的参数。

就我个人而言,您似乎在尝试测试您的 class,但同时模拟它,以便并非所有 class 都运行。 认为这是不正确的,实际上你怎么知道反序列化代码工作正常?

如果您的答案是另一个测试,您在 class 中模拟其他功能,我会回答说您需要将 BankInfo 的反序列化功能抽象到另一个 interface/class您可以模拟并将其注入您的 IBankInfoValidator

这意味着您将验证从对象的反序列化中分离出来,这将有助于测试和将来 maintainability/extensibility 如果您的用例发生变化。

就我个人而言,我现在会放弃您的测试,开始寻求抽象出对象的反序列化,然后考虑将其作为单独的 classes 进行测试。

回答你的问题

The problem is that my var result always returns null. I don't understand what am I doing wrong?

ValidateInputBankFile 永远不会设置并且您使用松散的模拟,因此它将 return 为空。

通过在 mock 的构造函数中传递 MockBehavior.Strict 来使用 Strict mocks,您将有一个异常告诉您您的方法未设置。

将设置应用到 return 该模拟上 ValidateInputBankFile 方法的适当值,它将正确运行。

忠告

您正在测试中的模拟对象上调用方法:

var result = mocSerializer.Object.ValidateInputBankFile(null, App.BankType.UniCredit);

根据经验,您永远不应该在 xxx.Object.MyMethod()

上调用方法

你不应该这样做的原因是因为你基本上只是在调用测试的 "arrange" 部分。

我觉得我需要问你这样做想达到什么目的,因为你基本上只是在测试你的测试