如何使用 Moq 对 WEB API 控制器异常进行单元测试
How to Unit test WEB API Controller Exception using Moq
如何对状态代码为 500 和消息的 IHttpActionResult 异常 InternalServerError 进行单元测试
[HttpGet]
public async Task<IHttpActionResult> Get(Guid myId)
{
try
{
var myaccount = await _myaccountService.GetMyAccount(myId);
return Ok(myaccount);
}
catch (Exception ex)
{
return InternalServerError();
}
}
是否尝试过测试方法
[TestMethod]
public async Task GeMyAccount_WhenThrowsException_ReturnsServerError()
{
// Arrange
var exception = new Exception("Internal Server Error");
var expectedResult = new List<MyAccount>
{
new MyAccount
{
Id = "1",
Name = "Name1"
},
new MyAccount
{
Id = "2",
Name = "Name2"
},
};
var myId = new Guid();
//Act
var mockMyAccountService = new Mock<IMyAccountService>();
mockMyAccountService.Setup(mock =>
mock.GetMyAccount(myId)).Throws(exception).Verifiable();
var controller = new MyAccountController(mockMyAccountService.Object);
//Assert
var actualResult = (await controller.Get(myId) as
OkNegotiatedContentResult<MyAccount>).Content;
?? var result = actualResult as ObjectResult;
?? Assert.AreEqual(StatusCodes.Status500InternalServerError, result.StatusCode);
?? Assert.AreEqual("Internal Server Error ", result.Value);
mockMyAccountService.Verify(b => b.GetMyAccount(myId));
}
不确定如何使用 Moq 获取异常和状态代码 500。
看看这段代码
[Fact]
public async Task Test1()
{
//arrange
//prepare your data for test
//act
async Task action()
{
//run your sut action
}
//assert
var exception = await Assert.ThrowsAsync<Exception>(action);
Assert.Equal("Internal Server Error", exception.Message);
}
正如 Nkosi 所说,异常被 try-catch 块吞没,因此您无法对异常做出任何断言。
但是您可以(并且应该)对返回的对象进行断言。
[TestMethod]
public async Task GivenAFaultyMyAccountService_WhenICallGet_ThenItReturnsAnInternalServerError()
{
//Arrange
var expectedException = new Exception("Something went wrong");
var mockMyAccountService = new Mock<IMyAccountService>();
mockMyAccountService
.Setup(svc => svc.GetMyAccount(It.IsAny<Guid>()))
.Throws(expectedException);
var sut = new MyAccountController(mockMyAccountService.Object);
//Act
var actualResult = await sut.Get(Guid.NewGuid());
//Assert
Assert.IsInstanceOfType(actualResult, typeof(InternalServerErrorResult));
}
我对您的测试进行了以下更改:
- 我已重命名您的测试以符合 Given-When-Then structure
- 在这个测试用例中,我只关注 单一 情况,当底层依赖发生故障时,所以我摆脱了与快乐之路相关的一切
- 快乐之路应该有一个单独的测试用例
- 我通过将
myId
参数替换为 It.IsAny<Guid>()
使模拟 Setup
更通用
- 我也将
new Guid()
替换为 Guid.NewGuid()
因为前者会创建一个空的 uuid,而后者会生成一个新的 uuid
- 我删除了
Verifiable
调用,因为这里并不真正需要它
- Act 阶段是您对给定方法进行实际调用时,而不是在构建控制器时,因此我已将评论移至正确位置
- 我把变量名
controller
改成sut
,代表System Under Test
- 我已将难以阅读的评估逻辑替换为简单的类型检查
InternalServerError
returns 一个 InternalServerErrorResult
- MSTest的
Assert
class有一个方法叫做IsInstanceOf,让类型检查更方便
如何对状态代码为 500 和消息的 IHttpActionResult 异常 InternalServerError 进行单元测试
[HttpGet]
public async Task<IHttpActionResult> Get(Guid myId)
{
try
{
var myaccount = await _myaccountService.GetMyAccount(myId);
return Ok(myaccount);
}
catch (Exception ex)
{
return InternalServerError();
}
}
是否尝试过测试方法
[TestMethod]
public async Task GeMyAccount_WhenThrowsException_ReturnsServerError()
{
// Arrange
var exception = new Exception("Internal Server Error");
var expectedResult = new List<MyAccount>
{
new MyAccount
{
Id = "1",
Name = "Name1"
},
new MyAccount
{
Id = "2",
Name = "Name2"
},
};
var myId = new Guid();
//Act
var mockMyAccountService = new Mock<IMyAccountService>();
mockMyAccountService.Setup(mock =>
mock.GetMyAccount(myId)).Throws(exception).Verifiable();
var controller = new MyAccountController(mockMyAccountService.Object);
//Assert
var actualResult = (await controller.Get(myId) as
OkNegotiatedContentResult<MyAccount>).Content;
?? var result = actualResult as ObjectResult;
?? Assert.AreEqual(StatusCodes.Status500InternalServerError, result.StatusCode);
?? Assert.AreEqual("Internal Server Error ", result.Value);
mockMyAccountService.Verify(b => b.GetMyAccount(myId));
}
不确定如何使用 Moq 获取异常和状态代码 500。
看看这段代码
[Fact]
public async Task Test1()
{
//arrange
//prepare your data for test
//act
async Task action()
{
//run your sut action
}
//assert
var exception = await Assert.ThrowsAsync<Exception>(action);
Assert.Equal("Internal Server Error", exception.Message);
}
正如 Nkosi 所说,异常被 try-catch 块吞没,因此您无法对异常做出任何断言。
但是您可以(并且应该)对返回的对象进行断言。
[TestMethod]
public async Task GivenAFaultyMyAccountService_WhenICallGet_ThenItReturnsAnInternalServerError()
{
//Arrange
var expectedException = new Exception("Something went wrong");
var mockMyAccountService = new Mock<IMyAccountService>();
mockMyAccountService
.Setup(svc => svc.GetMyAccount(It.IsAny<Guid>()))
.Throws(expectedException);
var sut = new MyAccountController(mockMyAccountService.Object);
//Act
var actualResult = await sut.Get(Guid.NewGuid());
//Assert
Assert.IsInstanceOfType(actualResult, typeof(InternalServerErrorResult));
}
我对您的测试进行了以下更改:
- 我已重命名您的测试以符合 Given-When-Then structure
- 在这个测试用例中,我只关注 单一 情况,当底层依赖发生故障时,所以我摆脱了与快乐之路相关的一切
- 快乐之路应该有一个单独的测试用例
- 我通过将
myId
参数替换为It.IsAny<Guid>()
使模拟 - 我也将
new Guid()
替换为Guid.NewGuid()
因为前者会创建一个空的 uuid,而后者会生成一个新的 uuid - 我删除了
Verifiable
调用,因为这里并不真正需要它 - Act 阶段是您对给定方法进行实际调用时,而不是在构建控制器时,因此我已将评论移至正确位置
- 我把变量名
controller
改成sut
,代表System Under Test - 我已将难以阅读的评估逻辑替换为简单的类型检查
InternalServerError
returns 一个 InternalServerErrorResult- MSTest的
Assert
class有一个方法叫做IsInstanceOf,让类型检查更方便
Setup
更通用