C# 如何测试.NET Core 3.1中响应内容中不返回数据的控制器POST方法?
我不熟悉集成测试。我有一个控制器方法,可以将用户添加到数据库中,如下所示:C# 如何测试.NET Core 3.1中响应内容中不返回数据的控制器POST方法?,c#,asp.net-core,testing,integration-testing,xunit,C#,Asp.net Core,Testing,Integration Testing,Xunit,我不熟悉集成测试。我有一个控制器方法,可以将用户添加到数据库中,如下所示: [HttpPost] public async Task<IActionResult> CreateUserAsync([FromBody] CreateUserRequest request) { try { var command = new CreateUserCommand { Login = request.Login,
[HttpPost]
public async Task<IActionResult> CreateUserAsync([FromBody] CreateUserRequest request)
{
try
{
var command = new CreateUserCommand
{
Login = request.Login,
Password = request.Password,
FirstName = request.FirstName,
LastName = request.LastName,
MailAddress = request.MailAddress,
TokenOwnerInformation = User
};
await CommandBus.SendAsync(command);
return Ok();
}
catch (Exception e)
{
await HandleExceptionAsync(e);
return StatusCode(StatusCodes.Status500InternalServerError,
new {e.Message});
}
}
我不确定仅仅断言从服务器返回的响应的状态代码是否足够。我很困惑,因为,我不知道,我应该附加到断言部分代码,这将获得所有用户,并检查它是否包含创建的用户,例如。我甚至没有这样一个用户的任何id,因为我的应用程序在将该用户添加到数据库时为该用户找到了一个新id。我也不知道如何测试这样的方法:
[HttpGet("{userId:int}")]
public async Task<IActionResult> GetUserAsync([FromRoute] int userId)
{
try
{
var query = new GetUserQuery
{
UserId = userId,
TokenOwnerInformation = User
};
var user = await QueryBus
.SendAsync<GetUserQuery, UserDto>(query);
var result = user is null
? (IActionResult) NotFound(new
{
Message = (string) _stringLocalizer[UserConstants.UserNotFoundMessageKey]
})
: Ok(user);
return result;
}
catch (Exception e)
{
await HandleExceptionAsync(e);
return StatusCode(StatusCodes.Status500InternalServerError,
new {e.Message});
}
}
[HttpGet(“{userId:int}”)]
公共异步任务GetUserAsync([FromRoute]int userId)
{
尝试
{
var query=newgetuserquery
{
UserId=UserId,
TokenOwnerInformation=用户
};
var user=await QueryBus
.SendAsync(查询);
var result=用户为空
?(IActionResult)未找到(新)
{
消息=(字符串)\u stringLocalizer[UserConstants.UserNotFoundMessageKey]
})
:Ok(用户);
返回结果;
}
捕获(例外e)
{
等待处理异常同步(e);
返回状态代码(StatusCodes.Status500InternalServerError,
新的{e.Message});
}
}
我认为我应该首先在Arrange部分创建一个用户,获取它的id,然后在Act部分中使用它,使用HttpClient发送的请求调用的GetUserAsync方法。同样的问题-在创建之后,没有返回关于用户的信息(顺便说一句,由于我在整个应用程序中的CQRS设计,它没有返回,命令不返回任何信息)。你能给我解释一下如何正确地编写这样的测试吗?我错过什么了吗?谢谢您的帮助。我就是这样做的:
var response = (CreatedResult) await _controller.Post(createUserRequest);
response.StatusCode.Should().Be(StatusCodes.Status201Created);
上面的第二行不是必需的,只是用于说明
另外,在Post动词上返回201(已创建)而不是200(确定)时,您的响应会更好,例如:
return Created($"api/users/{user.id}", user);
要测试NotFound的:
var result = (NotFoundObjectResult) await _controller.Get(id);
result.StatusCode.Should().Be(StatusCodes.Status404NotFound);
NotFoundObjectResult
假定您正在返回某些内容。如果您只是用404响应而没有解释,请将NotFoundObjectResult
替换为NotFoundResult
最后,请注意以下错误:
var result = (ObjectResult) await _controller.Get(id);
result.StatusCode.Should().Be(StatusCodes.Status500InternalServerError);
你可以用这个。这是集成测试的自动夹具替代方案
文档中的示例使用Get调用,但您也可以执行其他调用。从逻辑上讲,您应该测试状态代码(OkObjectResult
means 200)值和响应(可能是空字符串,这根本没有问题)
下面是一个记录在案的普通Get调用示例
[Fact]
public async Task GetTest()
{
// arrange
using (var fixture = new Fixture<Startup>())
{
using (var mockServer = fixture.FreezeServer("Google"))
{
SetupStableServer(mockServer, "Response");
var controller = fixture.Create<SearchEngineController>();
// act
var response = await controller.GetNumberOfCharacters("Hoi");
// assert
var request = mockServer.LogEntries.Select(a => a.RequestMessage).Single();
Assert.Contains("Hoi", request.RawQuery);
Assert.Equal(8, ((OkObjectResult)response.Result).Value);
}
}
}
private void SetupStableServer(FluentMockServer fluentMockServer, string response)
{
fluentMockServer.Given(Request.Create().UsingGet())
.RespondWith(Response.Create().WithBody(response, encoding: Encoding.UTF8)
.WithStatusCode(HttpStatusCode.OK));
}
这很简单:您不能编写一个在HTTP200之外断言的集成测试,这是异步应用程序的本质。如果确实需要更多断言,则需要进行自动化/端到端测试,其中创建一个随机用户并等待(动态重试),直到系统能够在实际数据库中创建该用户。作为可以作为构建的一部分运行的集成层测试,您的代码只需断言OK响应就可以了
[Fact]
public async Task GetTest()
{
// arrange
using (var fixture = new Fixture<Startup>())
{
using (var mockServer = fixture.FreezeServer("Google"))
{
SetupStableServer(mockServer, "Response");
var controller = fixture.Create<SearchEngineController>();
// act
var response = await controller.GetNumberOfCharacters("Hoi");
// assert
var request = mockServer.LogEntries.Select(a => a.RequestMessage).Single();
Assert.Contains("Hoi", request.RawQuery);
Assert.Equal(8, ((OkObjectResult)response.Result).Value);
}
}
}
private void SetupStableServer(FluentMockServer fluentMockServer, string response)
{
fluentMockServer.Given(Request.Create().UsingGet())
.RespondWith(Response.Create().WithBody(response, encoding: Encoding.UTF8)
.WithStatusCode(HttpStatusCode.OK));
}
using (var fixture = new RefitFixture<Startup, ISearchEngine>(RestService.For<ISearchEngine>))
{
using (var mockServer = fixture.FreezeServer("Google"))
{
SetupStableServer(mockServer, "Response");
var refitClient = fixture.GetRefitClient();
var response = await refitClient.GetNumberOfCharacters("Hoi");
await response.EnsureSuccessStatusCodeAsync();
var request = mockServer.LogEntries.Select(a => a.RequestMessage).Single();
Assert.Contains("Hoi", request.RawQuery);
}
}