我正在尝试在我的DAO类中模拟IDbConnection,但我收到以下错误:
字符串长度均为5.字符串在索引0处不同。 预计:“11111” 但是:“22222”
这是我的代码:
正在测试的课程
internal class ImportAcquisitionDataDAO : IImportAcquisitionDataDAO
{
private static Logger log = LogManager.GetCurrentClassLogger();
private readonly IDbConnection connection;
internal ImportAcquisitionDataDAO(IDbConnection connection)
{
this.connection = connection;
}
internal List<DefinitionEntry> GetDefinitions()
{
log.Debug("Getting definitions from database.");
var definitions = new List<DefinitionEntry>();
using (connection)
{
connection.Open();
log.Trace("Database connection opened");
IDbCommand command = connection.CreateCommand();
command.CommandText = @"SELECT *
FROM MAPPING";
IDataReader reader = command.ExecuteReader();
log.Trace("Command executed:\n{0}", command.CommandText);
definitions = GetMeterEntries(reader);
}
log.Debug("Obtained {0} definitions.", definitions.Count);
return definitions;
}
private List<DefinitionEntry> GetMeterEntries(IDataReader reader)
{
log.Trace("Parsing definitions from response");
var result = new List<DefinitionEntry>();
while (reader.Read())
{
var definition = new DefinitionEntry(
reader.GetString(0),
reader.GetString(1),
reader.GetString(2),
reader.IsDBNull(3) ? null : reader.GetString(3),
reader.IsDBNull(4) ? null : reader.GetString(4),
reader.IsDBNull(5) ? null : reader.GetString(5),
reader.IsDBNull(6) ? null : reader.GetString(6)
);
log.Trace(definition.ToString());
result.Add(definition);
}
return result;
}
}
public class DefinitionEntry
{
public string MeterSN { get; private set; }
public string MATNR { get; private set; }
public string IpAddress { get; private set; }
public string SIM { get; private set; }
public string ModulID { get; private set; }
public string SIMUser { get; private set; }
public string SIMPassword { get; private set; }
public DefinitionEntry(string meterSN, string matnr, string ipAddress, string sim, string modulId, string simUser, string simPassword)
{
MeterSN = meterSN;
MATNR = matnr;
IpAddress = ipAddress;
SIM = sim;
ModulID = modulId;
SIMUser = simUser;
SIMPassword = simPassword;
}
}
测试类
[TestFixture]
public class ImportAcquisitionDataDAOTests
{
private IDbConnection mockConnection;
private IDbCommand mockCommand;
private IDataReader mockReader;
private ImportAcquisitionDataDAO dao;
[SetUp]
public void SetUp()
{
mockConnection = Substitute.For<IDbConnection>();
mockCommand = Substitute.For<IDbCommand>();
mockReader = Substitute.For<IDataReader>();
dao = new ImportAcquisitionDataDAO(mockConnection);
mockConnection.CreateCommand().Returns(mockCommand);
mockCommand.ExecuteReader().Returns(mockReader);
}
[Test]
public void TestGetDefinitions()
{
// mock
var databaseDefinitionFirst = new DefinitionEntry("11111", "AS3000-5/100-400-P", "10.42.42.26", "SIM-001", "12345lkj", "alibaba", "abrakadabra");
var databaseDefinitionSecond = new DefinitionEntry("22222", "AS3000-5/100-400-Q", "10.42.42.158", null, null, null, null);
mockReader.Read().Returns(true, true, false);
mockReader.GetString(Arg.Is<int>(0)).Returns(databaseDefinitionFirst.MeterSN, databaseDefinitionSecond.MeterSN);
mockReader.GetString(Arg.Is<int>(1)).Returns(databaseDefinitionFirst.MATNR, databaseDefinitionSecond.MATNR);
mockReader.GetString(Arg.Is<int>(2)).Returns(databaseDefinitionFirst.IpAddress, databaseDefinitionSecond.IpAddress);
mockReader.IsDBNull(Arg.Is<int>(3)).Returns(false, true);
mockReader.GetString(Arg.Is<int>(3)).Returns(databaseDefinitionFirst.SIM);
mockReader.IsDBNull(Arg.Is<int>(4)).Returns(false, true);
mockReader.GetString(Arg.Is<int>(4)).Returns(databaseDefinitionFirst.ModulID);
mockReader.IsDBNull(Arg.Is<int>(5)).Returns(false, true);
mockReader.GetString(Arg.Is<int>(5)).Returns(databaseDefinitionFirst.SIMUser);
mockReader.IsDBNull(Arg.Is<int>(6)).Returns(false, true);
mockReader.GetString(Arg.Is<int>(6)).Returns(databaseDefinitionFirst.SIMPassword);
// use
List<DefinitionEntry> tested = dao.GetDefinitions();
// verify
Assert.AreEqual(2, tested.Count);
AssertDefinitionEntry(databaseDefinitionFirst, tested.First());
AssertDefinitionEntry(databaseDefinitionSecond, tested.Last());
}
private void AssertDefinitionEntry(DefinitionEntry expected, DefinitionEntry tested)
{
Assert.AreEqual(expected.MeterSN, tested.MeterSN);
Assert.AreEqual(expected.MATNR, tested.MATNR);
Assert.AreEqual(expected.IpAddress, tested.IpAddress);
Assert.AreEqual(expected.SIM, tested.SIM);
Assert.AreEqual(expected.ModulID, tested.ModulID);
Assert.AreEqual(expected.SIMUser, tested.SIMUser);
Assert.AreEqual(expected.SIMPassword, tested.SIMPassword);
}
}
这是执行第一个Assert之前的调试屏幕: enter image description here
除了MeterSN字段之外,我都按照我的预期设置,两个条目都相同。但我无法找出原因
答案 0 :(得分:0)
这是一个非常微妙的问题。
简短回答:
将mockReader.GetString(Arg.Is<int>(0)).Returns(databaseDefinitionFirst.MeterSN, databaseDefinitionSecond.MeterSN);
移至最后一次调用存根(位于mockReader.GetString(Arg.Is<int>(6))
下方)。
更长的答案:
当我们说mockReader.GetString(Arg.Is<int>(5))
时,Arg.Is
部分返回零,这意味着mockReader.GetString(0)
在测试设置中被多次调用。所以“11111”确实首先按照配置返回,但是当调用GetDefinitions
时,该值已经被消耗掉了。
顺便提一下,NSubstitute将mockReader.GetString(5).Returns(...)
视为与mockReader.GetString(Arg.Is<int>(5))
相同,这会简化您的代码。
另外,我建议尝试找到use a real data reader in your tests的方法。像下面这样的东西可以让你避免嘲笑那种类型的细节:
DataTable dt = new DataTable();
dt.Columns.AddRange(
new [] {
new DataColumn("a", typeof(string)),
new DataColumn("b", typeof(string)),
new DataColumn("c", typeof(string)),
new DataColumn("d", typeof(string)),
new DataColumn("e", typeof(string)),
new DataColumn("f", typeof(string)),
new DataColumn("g", typeof(string))
});
dt.Rows.Add("11111", "AS3000-5/100-400-P", "10.42.42.26", "SIM-001", "12345lkj", "alibaba", "abrakadabra");
dt.Rows.Add("22222", "AS3000-5/100-400-Q", "10.42.42.158", null, null, null, null);
mockReader = new DataTableReader(dt);
然后,您可以从测试中删除所有模拟设置。通过一些调整(例如,一些辅助方法来执行诸如databaseDefinitionFirst
之类的预期对象自动填充读者的方法)这可以形成一种测试与读者交互的所有代码的好方法,而不是必须伪造一切都在外面。