【问题标题】:Mocking SQL output parameter模拟 SQL 输出参数
【发布时间】:2010-06-10 12:33:29
【问题描述】:

我模拟了我的数据访问层的几个方法,但在某些方法中设置了 SQL 输出参数的值。我怎么能嘲笑这个?

方法:

var wrappedParameters = new SqlParameter[3];
            wrappedParameters[0] = new SqlParameter("@username",username);
            wrappedParameters[1] = new SqlParameter("@password",password);
            wrappedParameters[2] = new SqlParameter("returnValue",SqlDbType.Int) { Direction =ParameterDirection.ReturnValue };

            dal.ExecuteUsingStoredProcedure("GetUser", wrappedParameters);

模拟(我尝试使用“OutRef”,但这不起作用):

using (mocks.Record())
        {
            Expect.Call(dal.ExecuteUsingStoredProcedure("",> null)).Return(true).IgnoreArguments().OutRef(1);
        }

但这没有用。当我执行 SP GetUser 时,设置了参数返回值,但我不知道如何模拟它

【问题讨论】:

  • 在可能的情况下尝试使用 IDbParameter 而不是 SqlParameter,然后你就可以尽情地模拟了。

标签: unit-testing mocking rhino-mocks


【解决方案1】:

我认为你的做法是错误的。您的 DAL 界面应如下所示:

/// <summary>
/// Models a service which holds the user information.
/// </summary>
public interface IUserRepository
{
   /// <summary>
   /// Gets the user with the given name, or <c>null</c> if no user with
   /// that name and password exists.
   /// </summary>
   /// <exception cref="IOException">
   /// An I/O problem occurred while accessing the repository.
   /// </exception>
   User TryGetUser(string name, string password);
}

DAL 抽象现在隐藏了使用存储过程的事实。事实上,DAL 甚至可能不是数据库:它可能是磁盘上的文本文件、网络服务、模拟或其他任何东西。

为了测试使用 DAL 的代码而模拟 DAL 现在变得微不足道。在这些示例中,我选择了登录屏幕的view model(又名presentation model)作为待测系统:

[Test]
public void Login_sets_user_and_goes_to_main_screen_when_TryGetUser_not_null()
{
    var userRepositoryStub = MockRepository.GenerateStub<IUserRepository>();
    var user = new User(...);
    userRepositoryStub.Stub(x=>x.GetUserByName("foo","bar")).Return(user);
    var sessionStub = MockRepository.GenerateStub<ISession>();
    var loginScreenViewModel = 
        new LoginScreenViewModel(sessionStub, userRepositoryStub);

    loginScreenViewModel.UserName = "foo";
    loginScreenViewModel.Password = "bar";
    loginScreenViewModel.Login();

    userRepositoryStub.AssertWasCalled(x=>x.TryGetUser("foo","bar"));
    sessionStub.AssertWasCalled(x=>x.ShowMainScreen());
    Assert.AreEqual(user, session.User);
}

.

[Test]
public void Login_shows_error_when_TryGetUser_returns_null()
{
    var userRepositoryStub = MockRepository.GenerateStub<IUserRepository>();
    var sessionStub = MockRepository.GenerateStub<ISession>();
    var loginScreenViewModel = 
        new LoginScreenViewModel(sessionStub, userRepositoryStub);

    loginScreenViewModel.UserName = "foo";
    loginScreenViewModel.Password = "bar";
    loginScreenViewModel.Login();

    Assert.AreEqual(loginScreenViewModel.Error, 
        "User 'foo' does not exist or password is incorrect"));
    userRepositoryStub.AssertWasCalled(x=>x.TryGetUser("foo","bar"));
    sessionStub.AssertWasNotCalled(x=>x.ShowMainScreen());
    Assert.IsNull(session.User);
}

【讨论】:

    【解决方案2】:

    我认为你不能模拟它,因为它是一个普通的 SqlParameter(具体类),而不是 .Net 意义上的 out/ref 参数。我会尝试在对 dal 的模拟调用中简单地设置参数的值(我没有检查语法,但我相信你明白了):

    using (mocks.Record())
            {
                Expect.Call(dal.ExecuteUsingStoredProcedure("",null)).Return(true).IgnoreArguments().Do(x => wrappedParameters[2].Value = 1; true);
            }
    

    【讨论】:

      【解决方案3】:

      我使用“WhenCalled”方法对此进行了存根。

      在我的代码(待测试)中,我首先创建连接和命令并添加三个参数,其中第三个是我的输出参数。然后我在这个上调用“ExecuteCommand”......我不会通过这个代码,因为我认为它是相当标准的(ExecuteCommand 将命令对象作为它的参数)。

      在我的测试中,我为我的 sql 数据服务创建了一个存根并对其进行编程,以便设置参数的值:

      var sqlService = MockRepository.GenerateStub<ISqlDataService>();
      sqlService.Stub(s => s.ExecuteCommand(null))
          .IgnoreArguments()
          .WhenCalled(s => ((SqlCommand)s.Arguments[0]).Parameters[2].Value = expectedValue)
          .Return(0);
      

      对于您的项目来说,答案可能有点晚了,但希望这对某人有所帮助......

      格里夫

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-08
        • 1970-01-01
        • 1970-01-01
        • 2011-03-28
        相关资源
        最近更新 更多