简体   繁体   English

MOQ单元测试-返回类型

[英]MOQ unit test - Return type

I am very new to MOQ and have an issue I cannot solve. 我起订量很陌生,有一个我无法解决的问题。 I have the following code I am testing (I am testing first one - ValidateInputBankFile ): 我正在测试以下代码(我正在测试第一个代码-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;
    }

This is my test method: 这是我的测试方法:

    [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());
    }

What I am trying to do, is to avoid call to DeserializeBankInfo , return new IP_BankInfo and so that I can check it under my final assert stage. 我想做的是避免调用DeserializeBankInfo ,返回新的IP_BankInfo ,以便我可以在最后的assert阶段对其进行检查。

The problem is that my var result always returns null. 问题是我的var结果总是返回null。 I don't understand what am I doing wrong? 我不明白我在做什么错?

Also it fails on the following code mocSerializer.Setup(n => n.DeserializeBankInfo(App.BankType.UniCredit)).Returns(()=>null); 同样在以下代码上失败mocSerializer.Setup(n => n.DeserializeBankInfo(App.BankType.UniCredit)).Returns(()=>null); , yet I am passing correct parameters. ,但是我传递了正确的参数。

To answer your question 回答你的问题

The problem is that my var result always returns null. 问题是我的var结果总是返回null。 I don't understand what am I doing wrong? 我不明白我在做什么错?

ValidateInputBankFile is never setup and you use loose mocks, therefore it will return null. ValidateInputBankFile永远不会设置,并且您使用宽松的模拟,因此它将返回null。

Use Strict mocks by passing MockBehavior.Strict in the constructor of your mock and you will have an exception telling you that your method was not setup. 通过在模拟的构造函数中传递MockBehavior.Strict来使用严格的模拟,您将遇到一个异常,告诉您未设置方法。

Apply a Setup to return an appropriate value on that mock for the ValidateInputBankFile method and it will behave correctly. 应用安装程序以对该ValidateInputBankFile方法的该模拟返回适当的值,它将正常运行。

A word of advice 忠告

You are calling methods on a mocked object from within your test : 您正在从测试中调用模拟对象上的方法:

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

As a rule of thumb, you should never call method on a xxx.Object.MyMethod() 根据经验,永远不要在xxx.Object.MyMethod()上调用方法

the reason why you should not do that is because you're basically just calling your "arrange" part of the test. 之所以不应该这样做,是因为您基本上只是称呼测试的“安排”部分。

I feel like I need to ask you what you are trying to achieve by doing so, because you're basically just testing your test . 我觉得我需要问你要这样做的目的是什么,因为您基本上只是在测试自己的测试

Personally to me it looks like you are attempting to test your class but as the same time mock it so that not all of the class runs. 就我个人而言,您似乎正在尝试测试您的课程,但同时模拟了该课程,因此并非所有课程都在运行。 I see this as incorrect, effectively how do you know that the deserialisation code is working correctly? 认为这是不正确的,实际上,您如何知道反序列化代码正常工作?

If your answer is another test where you mock other functionality in your class I would reply saying that you need to abstract out the deserialisation functionality of the BankInfo into another interface/class that you can mock and inject this into your IBankInfoValidator . 如果您的答案是在类中模拟其他功能的另一个测试,我会回答说,您需要将BankInfo的反序列化功能抽象到另一个接口/类中,您可以模拟该接口/类并将其注入到IBankInfoValidator

This means that you are splitting out your validation from the deserialisation of the object, this will help both in testing and maintainability/extensibility in the future if your use case changes. 这意味着您正在将验证与对象的反序列化分离开来,如果用例发生变化,这将有助于将来的测试以及可维护性/可扩展性。

Personally I'd scrap your tests just now, start looking to abstract out the deserialisation of your object and then think about testing it as separate classes. 就我个人而言,我现在将废弃您的测试,开始寻求抽象化对象的反序列化,然后考虑将其作为单独的类进行测试。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM