如何断言异常类型和异常消息



这是我在XUnit中的测试方法。

[Fact]
public async Task AddCampaign_ReturnBadRequestWhenDateIsInvalid()
{
var client = _factory.CreateClient();
string title = string.Format("Test Add Campaign {0}", Guid.NewGuid());
var campaignAddDto = new CampaignDTORequest
{
Title = title
};
var encodedContent = new StringContent(JsonConvert.SerializeObject(campaignAddDto), Encoding.UTF8, "application/json");
var response = await client.PostAsync("/api/Campaign/add", encodedContent);
var responseString = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<CampaignDTOResponse>(responseString);
Assert.False(response.IsSuccessStatusCode);
Assert.ThrowsAsync<ArgumentNullException>(()=> client.PostAsync("/api/Campaign/add", encodedContent));
}

第一个断言是有效的。我被第二个断言卡住了。如何断言异常类型(ArgumentNullException(及其异常消息?

这是的服务方法

public async Task<Campaign> AddCampaignAsync(Campaign campaign)
{            
if (campaign.StartDate.Equals(DateTime.MinValue)) {
throw new ArgumentNullException("Start Date cannot be null or empty.");
}

await _context.Campaigns.AddAsync(campaign);
await _context.SaveChangesAsync();
return campaign;
}

根据雷阳的线索更新。

var exceptionDetails = Assert.ThrowsAsync<ArgumentNullException>(() => client.PostAsync("/api/Campaign/add", encodedContent));
Assert.Equal("Start Date cannot be null or empty.", exceptionDetails.Result.Message);

但仍然不起作用。

System.AggregateException:出现一个或多个错误。(Assert.Sthrows((失败应为:typeof(System.ArgumentNullException(实际:(未引发异常((

尝试了戴的解决方案,但仍然出现错误。

Assert.Throws() Failure
Expected: typeof(System.ArgumentNullException)
Actual:   (No exception was thrown)

这是我的API方法。

public async Task<ActionResult<CampaignDTOResponse>> AddCampaign([FromBody] CampaignDTORequest newCampaign)
{
try
{
var campaign = _mapper.Map<Campaign>(newCampaign);
campaign = await _campaignService.AddCampaignAsync(campaign);
var campaignDtoResponse = _mapper.Map<CampaignDTOResponse>(campaign);
return CreatedAtAction(nameof(GetCampaignById), new { id = campaignDtoResponse.Id }, campaignDtoResponse);
}
catch (Exception ex)
{
_logger.LogError(0, ex, ex.Message);
return Problem(ex.Message);
}
}

更新:我将检查从服务转移到api。

if (newCampaign.StartDate.Equals(DateTime.MinValue))
{
return BadRequest("Start Date cannot be null or empty.");
}

我在下面这样断言它们。

Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
Assert.Equal("Start Date cannot be null or empty.", responseString);

Assert.ThrowsAsync仍然是一个async Task方法,因此您需要await来确保任务继续(进行实际断言(能够正确运行:

[Fact]
public async Task AddCampaign_Return_bad_request_when_date_is_invalid()
{
[...]
Assert.False(response.IsSuccessStatusCode);
await Assert.ThrowsAsync<ArgumentNullException>(()=> client.PostAsync("/api/Campaign/add", encodedContent));
}

然而

  • 。。。。请重新考虑您的设计:例外情况应该是例外
    • 尽管并非所有都同意:https://softwareengineering.stackexchange.com/questions/184654/ive-been-told-that-exceptions-should-only-be-used-in-exceptional-cases-how-do
    • 尽管Java已经检查了异常,但使用异常来表示各种错误条件是有意义的,而不仅仅是异常错误条件-而C#/.NET没有检查异常,因此需要人们阅读手写文档来查看声明的异常是什么,如果有的话-这使得.NET中的正确错误处理相当痛苦,除非您同意只在异常条件下抛出,而是使用返回类型来表示非异常错误条件
  • 即使您想抛出,也不应该抛出ArgumentNullException来表示HTTP400错误请求响应。
    • ArgumentException类及其子类(ArgumentNullExceptionArgumentOutOfRangeException等(只能用于指示失败的前置条件,而不是失败的后处理条件或内部错误(请使用InvalidOperationException(
    • 就我个人而言,我不认为web服务客户端应该为任何响应抛出异常,除非它实际上是一个"异常">异常";反应或情况
    • 如果您使用NSwag生成web服务客户端,那么它将为您生成ApiException<TResponse>,这将非常有用
    • 尽管我倾向于返回所有合理可能响应的有区别的并集(即[ProducesResponseType]声明的任何响应(

您可以使用Record.Exception捕获异常并断言它:

// Act
Action action = async () => await client.PostAsync("/api/Campaign/add", encodedContent);
var ex = Record.Exception(action);
// Assert
Assert.NotNull(ex);
Assert.IsType<ArgumentNullException>(ex);

最新更新