是否可以模拟数据库事务参数?
我正在尝试对接口的实现进行单元测试,但在成功模拟接口方法之一的 SqlTransaction 参数时遇到了一些困难。
这是我感兴趣的接口和测试方法的样子。
public class MyInterface
{
void MyMethod(SqlTransaction SharedTransaction, DateTime EventTime);
}
public class MyImplementation : MyInterface
{
public void MyMethod(SqlTransaction SharedTransaction, DateTime EventTime)
{
DateTime dtLastEventTime = DateTime.MinValue;
using(SqlCommand comm = SharedTransaction.Connection.CreateCommand())
{
comm.CommandText = SQL_GET_LAST_EVENTTIME_DEFINED_ELSEWHERE;
comm.Parameters.AddWithValue("ParamName", 123);
object oResult = comm.ExecuteScalar();
dtLastEventTime = DateTime.Parse(oResult.ToString());
}
//Do something with dtLastEventTime
}
}
我一直在使用 Moq 和各种语法方法来模拟数据库对象,但运气不佳。(我必须进行一些转换System.Data.Common 对象以便能够更进一步.. DbTransaction、DbConnection、DbCommand 等)。
我主要想知道是否可以通过这种方式模拟交易,或者我是否在这里找错了树。 幸运的是,我也许能够将接口转换为使用通用的 DbTransaction 参数,而不是特定于提供程序的 SqlTransaction,但我不相信这就是我在模拟方面遇到困难的原因。
这是(这可能是完全错误的,所以如果我不正确地处理这个问题,请纠正我或发表评论)到目前为止我所得到的模拟代码...
var mockParams = new Mock<DbParameterCollection>();
mockParams.Setup(p => p.Add(new SqlParameter("ParamName", 123)));
var mockCommand = new Mock<DbCommand>();
mockCommand.Setup(p => p.Parameters).Returns(mockParams.Object);
var mockConnection = new Mock<DbConnection>();
mockConnection.Setup(con => con.CreateCommand()).Returns(mockCommand.Object);
var mockTrans = new Mock<DbTransaction>();
mockTrans.Setup(t => t.Connection).Returns(mockConnection.Object);
但是,这似乎在mockCommand.Setup行上抛出一个ArgumentException .. (不可重写成员上的设置无效)
是否有人对我如何使用模拟的 SqlTransaction 参数正确地对该方法进行单元测试有任何想法或建议?
I'm trying to unit-test my implementation of an interface, and I'm having a little difficulty successfully mocking out a SqlTransaction parameter to one of the interface methods.
Here's what the interface, and method under test that I'm interested in look like..
public class MyInterface
{
void MyMethod(SqlTransaction SharedTransaction, DateTime EventTime);
}
public class MyImplementation : MyInterface
{
public void MyMethod(SqlTransaction SharedTransaction, DateTime EventTime)
{
DateTime dtLastEventTime = DateTime.MinValue;
using(SqlCommand comm = SharedTransaction.Connection.CreateCommand())
{
comm.CommandText = SQL_GET_LAST_EVENTTIME_DEFINED_ELSEWHERE;
comm.Parameters.AddWithValue("ParamName", 123);
object oResult = comm.ExecuteScalar();
dtLastEventTime = DateTime.Parse(oResult.ToString());
}
//Do something with dtLastEventTime
}
}
I've been using Moq and various syntax approaches to mock out the Database objects and not having much luck.. (I had to do some conversion to the System.Data.Common objects in order to be able to get a little further.. DbTransaction, DbConnection, DbCommand etc).
What I'd like to know is primarily whether it's possible to mock out a transaction in this way, or whether I'm barking up the wrong tree here. Luckily I may be able to get the interface converted to use a generic DbTransaction parameter rather than the provider-specific SqlTransaction, but I'm not convinced that's why I'm having a hard time with the mocking.
Here's (and this could be completely wrong, so please correct me or comment if i'm approaching this incorretly) what I've got so far for mocking code...
var mockParams = new Mock<DbParameterCollection>();
mockParams.Setup(p => p.Add(new SqlParameter("ParamName", 123)));
var mockCommand = new Mock<DbCommand>();
mockCommand.Setup(p => p.Parameters).Returns(mockParams.Object);
var mockConnection = new Mock<DbConnection>();
mockConnection.Setup(con => con.CreateCommand()).Returns(mockCommand.Object);
var mockTrans = new Mock<DbTransaction>();
mockTrans.Setup(t => t.Connection).Returns(mockConnection.Object);
However, this seems to throw an ArgumentException on the mockCommand.Setup line..
(Invalid setup on a non-overridable member)
Does anyone have any ideas or suggestions on how I might be able to correctly unit-test this method with a mocked SqlTransaction parameter?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
Peter,我将假设 SqlServer 后端。
首先,我将重构 MyMethod(),将 MyMethod() 上的入站参数类型更改为 IDbTransaction,以便您可以传入模拟。 然后我会抽象出 ExecuteScalar() 调用,以便我可以轻松地检查测试中的 SqlCommand 参数。
由于 Moq 支持递归模拟,因此在测试中我将模拟对共享事务的调用,如下所示:
再创建一个模拟来检查方法中的命令参数,并在 ExecuteScalar() 调用上返回一个值,然后就完成了!
重构 MyMethod():
测试:
就个人而言,我喜欢测试 SqlCommand 调用上的参数,因此我在示例中从这个角度解决了您的问题。
Peter, I am going to assume SqlServer backend.
First off, I would refactor MyMethod() by changing the inbound parameter type to IDbTransaction on MyMethod() so you can pass in your mock. Then I would abstract away the ExecuteScalar() call so I could easily check the SqlCommand parameters in my test.
Since Moq supports recursive mocking, in the test I would mock the call on sharedTransaction like this:
Create one more mock for checking the command parameters in your method, and returning a value on the ExecuteScalar() call, and your done!
Refactored MyMethod():
The test:
Personally, I like to test the parameters on my SqlCommand calls, so I attacked your problem from this angle in my example.