lan*_*der 36 c# unit-testing moq mocking
我是moq的新手,并设置了模拟,所以我可以做一些帮助.如何使用Moq模拟SqlDataReader?
更新
经过进一步测试,这是我到目前为止所做的:
private IDataReader MockIDataReader()
{
var moq = new Mock<IDataReader>();
moq.Setup( x => x.Read() ).Returns( true );
moq.Setup( x => x.Read() ).Returns( false );
moq.SetupGet<object>( x => x["Char"] ).Returns( 'C' );
return moq.Object;
}
private class TestData
{
public char ValidChar { get; set; }
}
private TestData GetTestData()
{
var testData = new TestData();
using ( var reader = MockIDataReader() )
{
while ( reader.Read() )
{
testData = new TestData
{
ValidChar = reader.GetChar( "Char" ).Value
};
}
}
return testData;
}
Run Code Online (Sandbox Code Playgroud)
你做读者时的问题.在我的GetTestData()方法中,它总是空的.我需要知道如何做类似的事情
reader.Stub( x => x.Read() ).Repeat.Once().Return( true )
Run Code Online (Sandbox Code Playgroud)
Mon*_*nor 61
Moq能够在执行方法后运行一些代码.它被称为"回调".以这种方式修改您的代码,它将工作:
private IDataReader MockIDataReader()
{
var moq = new Mock<IDataReader>();
bool readToggle = true;
moq.Setup(x => x.Read())
// Returns value of local variable 'readToggle' (note that
// you must use lambda and not just .Returns(readToggle)
// because it will not be lazy initialized then)
.Returns(() => readToggle)
// After 'Read()' is executed - we change 'readToggle' value
// so it will return false on next calls of 'Read()'
.Callback(() => readToggle = false);
moq.Setup(x => x["Char"])
.Returns('C');
return moq.Object;
}
private class TestData
{
public char ValidChar { get; set; }
}
private TestData GetTestData()
{
var testData = new TestData();
using ( var reader = MockIDataReader() )
{
testData = new TestData
{
ValidChar = (Char)reader["Char"]
};
}
return testData;
}
Run Code Online (Sandbox Code Playgroud)
但是如果需要IDataReader不仅要包含单行,还要包含几行呢?好吧,这是一个示例:
// You should pass here a list of test items, their data
// will be returned by IDataReader
private IDataReader MockIDataReader(List<TestData> ojectsToEmulate)
{
var moq = new Mock<IDataReader>();
// This var stores current position in 'ojectsToEmulate' list
int count = -1;
moq.Setup(x => x.Read())
// Return 'True' while list still has an item
.Returns(() => count < ojectsToEmulate.Count - 1)
// Go to next position
.Callback(() => count++);
moq.Setup(x => x["Char"])
// Again, use lazy initialization via lambda expression
.Returns(() => ojectsToEmulate[count].ValidChar);
return moq.Object;
}
Run Code Online (Sandbox Code Playgroud)
mik*_*igs 12
我只是想弄清楚自己.不确定这是否是Moq中的新功能,但似乎有一种比@ Monsignor的答案更简单的方法.
使用Moq的SetupSequence方法.你的代码变成了:
private IDataReader MockIDataReader()
{
var moq = new Mock<IDataReader>();
moq.SetupSequence( x => x.Read() )
.Returns( true )
.Returns( false );
moq.SetupGet<object>( x => x["Char"] ).Returns( 'C' );
return moq.Object;
}
Run Code Online (Sandbox Code Playgroud)
这不会让您模拟 aSqlDataReader但如果您的函数返回 a DbDataReader( 的基类SqlDataReader)或IDataReader模拟它的简单方法就是使用 aDataTable或 aDataSet并调用其CreateDataReader()函数并返回它。
首先,在一个单独的项目中,像往常一样运行查询以生成一些测试数据,并使用WriteXmlSchema生成 .xsd 文件和WriteXml保存测试数据的函数。
using (var con = new SqlConnection(connectionString))
{
con.Open();
using (var cmd = new SqlCommand("Some query", con))
{
DataSet ds = new DataSet("TestDataSet");
DataTable dt = new DataTable("FirstSet");
ds.Tables.Add(dt);
using (var reader = cmd.ExecuteReader())
{
dt.Load(reader);
}
ds.WriteXmlSchema(@"C:\Temp\TestDataSet.xsd");
ds.WriteXml(@"C:\Temp\TestDataSetData.xml");
}
}
Run Code Online (Sandbox Code Playgroud)
在您的测试项目中添加TestDataSet.xsd到项目并确保它具有自定义工具MSDataSetGenerator(默认情况下应该有它)。这将导致生成具有查询架构的DataTable命名派生类TestDataSet。
然后TestDataSetData.xml作为资源添加到您的测试项目中。最后在您的测试中使用您生成的 xml 文件中的文本创建TestDataSet和调用ReadXml。
var resultSet = new TestData.TestDataSet();
using (var reader = new StringReader(Resources.TestDataSetData))
{
resultSet.ReadXml(reader);
}
var testMock = new Mock<DbCommand>();
testMock.Setup(x => x.ExecuteReader())
.Returns(resultSet.CreateDataReader);
testMock.Setup(x => x.ExecuteReaderAsync())
.ReturnsAsync(resultSet.CreateDataReader);
Run Code Online (Sandbox Code Playgroud)
这将创建一个数据读取器,它的行为就像从 sql 查询返回的数据读取器一样,甚至支持返回多个结果集之类的东西。
| 归档时间: |
|
| 查看次数: |
19983 次 |
| 最近记录: |