最小起订量单元测试 - 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" 部分。
我觉得我需要问你这样做想达到什么目的,因为你基本上只是在测试你的测试。
我对 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" 部分。
我觉得我需要问你这样做想达到什么目的,因为你基本上只是在测试你的测试。