【问题标题】:MOQ unit test - Return typeMOQ 单元测试 - 返回类型
【发布时间】:2015-10-12 13:43:32
【问题描述】:

我对最小起订量非常陌生,有一个我无法解决的问题。我正在测试以下代码(我正在测试第一个 - 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,返回新的IP_BankInfo,以便我可以在最后的断言阶段检查它。

问题是我的 var 结果 总是返回 null。我不明白我做错了什么?

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

【问题讨论】:

  • 您的测试中似乎只有一个模拟版本的类 - 您应该构造一个要测试的 实际类 的实例,传入模拟对象该类需要的任何内容,因此当它在测试期间调用这些方法时,您可以完全控制传递回被测类的信息。
  • 我可以创建IP_BankInfoDeserializer 的实例,但是当我调用ValidateInputBankFile 时,我不希望它调用DeserializeBank,因为它会调用XMLSerializer,而是直接返回我想要的。问题是我不知道如何绕过那个调用
  • 这时你可能需要引入另一个层,并传入一个负责与底层存储对话的接口给这个类。目前,您正在测试的单元(类)负责访问DeserializeBankInfo 中的磁盘,所以如果您正在测试这个单元,您将测试磁盘访问作为它的一部分。如果你想让它分开,你必须把它分成自己的单元。单元测试并不一定意味着测试单个函数——一个单元通常是整个类。
  • 在一个完全不相关的注释上——你可能想看看Path.Combine——会稍微清理一下流阅读器的结构。

标签: c# unit-testing moq


【解决方案1】:

回答您的问题

问题是我的 var 结果总是返回 null。我不明白我做错了什么?

ValidateInputBankFile 永远不会设置,并且您使用松散的模拟,因此它将返回 null。

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

应用设置以在该模拟上为 ValidateInputBankFile 方法返回一个适当的值,它会正确运行。

忠告

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

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

根据经验,您永远不应该在 xxx.Object.MyMethod() 上调用方法

您不应该这样做的原因是因为您基本上只是在调用测试的“安排”部分。

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

【讨论】:

    【解决方案2】:

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

    如果您的答案是另一个测试,您在课堂上模拟其他功能,我会回复说您需要将 BankInfo 的反序列化功能抽象到另一个接口/类中,您可以模拟并将其注入您的 @ 987654322@。

    这意味着您将验证与对象的反序列化分开,如果您的用例发生变化,这将有助于将来的测试和可维护性/可扩展性。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-12-07
      • 2015-09-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-04
      • 2010-12-10
      相关资源
      最近更新 更多