微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

C#/Moq - 如何强制异常并一步返回值

如何解决C#/Moq - 如何强制异常并一步返回值

我有一个使用以下方法的存储库 DoSomeWork

internal class MyRepository : IMyRepository
{
   public MyRepository(ILogger<MyRepository> logger,IDbContextwrapper dbContext)
   {
       this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
       this.dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext));
   }

   public Task<Result> DoSomeWork(int someInt)
   {
       return Task.Run(() =>
       {
           try
           {
               var parameters = new DynamicParameters(new { SomeIntValue = someInt });
               parameters.Add("WorkComplete",DbType.Boolean,direction: ParameterDirection.ReturnValue);
               dbContext.TransactionedExecute("NameOfStoredProcedure",parameters,CommandType.StoredProcedure); //This is a wrapper for Dapper (DbConnection)
               var status = (DoSomeWorkStatus)parameters.Get<int>("WorkComplete");
               var workComplete = status == DoSomeWorkStatus.Donesuccessfully;

               return workComplete ? Result.WorkDone : Result.NoworkDone;
           }
           catch(DatabaseTimeoutException dte)
           {
               logger.Loginformation(dte,"");
               return Result.Error;
           }
           catch(DatabaseDeadlockException dde)
           {
               logger.Loginformation(dde,"");
               return Result.Error;
           }
       });
    }
}

我想要实现的是测试和验证一旦在 try/catch 中捕获到 DatabaseTimeoutExceptionDatabaseDeadlockException,任务应该返回 Result.Error。而这一切都应该一步完成(无需重试)。

在测试中我有以下内容

private Mock<IMyRepository> myRepoMock;
private MyRepoManager target;

...

[SetUp]
public void SetUp()
{
   myRepoMock = new Mock<IMyRepository>();
   target = new MyRepoManager(myRepoMock.Object);
}

[Test]
public async Task MyMoqtest()
{
    //Arrange
    myRepoMock
      .Setup(mrm => mrm.DoSomeWork(It.IsAny<int>()))
      .Returns(Task.FromException<Result>(new DatabaseTimeoutException()));

    //myRepoMock
    //  .Setup(mrm => mrm.DoSomeWork(It.IsAny<int>()))
    //  .Throws<DatabaseTimeoutException>(); <- The same result as above

    //Act
    Result taskResult = await target.RunTask(int someInt); //Calls repository method - DoSomeWork

    //Assert
    Assert.AreEqual(Result.Error,taskResult.Result);
}

但是发生的情况是存储库抛出 DatabaseTimeoutException 而不返回 Result.Error,并且测试失败并显示消息(如预期):

MyExceptions.DatabaseTimeoutException : Exception of type 'MyExceptions.DatabaseTimeoutException' was thrown.

我对 Moq 非常陌生,所以我的问题是 - 这可以通过 Moq 来完成,如果可以,我将如何进行?

谢谢。

解决方法

单元测试最重要的部分是识别被测系统 (SUT)。这就是您实际要验证的工作。一旦你确定了这一点,你的 SUT 的所有依赖项都应该被模拟,这样你就可以严格控制你正在测试的东西外部的一切。

如果您尝试对 MyRepoManager.RunTask 进行单元测试,那么它不应该关心其依赖项的任何内部实现细节。它应该只关心他们公开的合同。在这种情况下,您依赖于 IMyRepository。所以具体实现 MyRepository 做了什么无关紧要。 MyRepository 可能会在内部处理 DatabaseTimeoutException 和 DatabaseDeadlockException,但这是一个实现细节,不是通过 IMyRepository 定义的合同的一部分。目标是模拟依赖项的行为,而不是在模拟框架内完全重新实现依赖项的内部行为。

因此,您的模拟设置应该是:

myRepoMock
    .Setup(mrm => mrm.DoSomeWork(It.IsAny<int>()))
    .Returns(Task.FromResult(Result.Error));

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?