J'ai un test xUnit comme:
[Fact]
public async void GetLocationsCountAsync_WhenCalled_ReturnsLocationsCount()
{
_locationsService.Setup(s => s.GetLocationsCountAsync("123")).ReturnsAsync(10);
var controller = new LocationsController(_locationsService.Object, null)
{
ControllerContext = { HttpContext = SetupHttpContext().Object }
};
var actionResult = await controller.GetLocationsCountAsync();
actionResult.Value.Should().Be(10);
VerifyAll();
}
La source est
/// <summary>
/// Get the current number of locations for a user.
/// </summary>
/// <returns>A <see cref="int"></see>.</returns>
/// <response code="200">The current number of locations.</response>
[HttpGet]
[Route("count")]
public async Task<ActionResult<int>> GetLocationsCountAsync()
{
return Ok(await _locations.GetLocationsCountAsync(User.APropertyOfTheUser()));
}
La valeur du résultat est nulle, ce qui entraîne l'échec de mon test, mais si vous regardez ActionResult.Result.Value
(une propriété interne), il contient la valeur résolue attendue.
Voir la capture d'écran suivante du débogueur.
Comment puis-je obtenir l'actionResult.Value à remplir dans un test unitaire?
Au moment de l'exécution, votre code d'origine testé fonctionnerait toujours en raison de la conversion implicite.
Mais sur la base de l'image du débogueur fournie, il semble que le test ait affirmé la mauvaise propriété du résultat.
Ainsi, tout en changeant la méthode sous test a permis au test de passer, cela aurait fonctionné lors de l'exécution en direct dans les deux sens
ActioResult<TValue>
A deux propriétés qui sont définies en fonction de ce qui est retourné par l'action qui l'utilise.
/// <summary>
/// Gets the <see cref="ActionResult"/>.
/// </summary>
public ActionResult Result { get; }
/// <summary>
/// Gets the value.
/// </summary>
public TValue Value { get; }
Ainsi, lorsque l'action du contrôleur est retournée à l'aide de Ok()
, elle définit la propriété ActionResult<int>.Result
Du résultat de l'action via une conversion implicite.
public static implicit operator ActionResult<TValue>(ActionResult result)
{
return new ActionResult<TValue>(result);
}
Mais le test affirmait la propriété Value
(voir l'image dans OP), qui dans ce cas n'était pas définie.
Sans avoir à modifier le code testé pour satisfaire le test, il aurait pu accéder à la propriété Result
et faire des assertions sur cette valeur
[Fact]
public async Task GetLocationsCountAsync_WhenCalled_ReturnsLocationsCount() {
//Arrange
_locationsService
.Setup(_ => _.GetLocationsCountAsync(It.IsAny<string>()))
.ReturnsAsync(10);
var controller = new LocationsController(_locationsService.Object, null) {
ControllerContext = { HttpContext = SetupHttpContext().Object }
};
//Act
var actionResult = await controller.GetLocationsCountAsync();
//Assert
var result = actionResult.Result as OkObjectResult;
result.Should().NotBeNull();
result.Value.Should().Be(10);
VerifyAll();
}
Le problème est de l'envelopper dans Ok
. Si vous renvoyez l'objet lui-même, Value
est correctement rempli.
Si vous regardez exemples de Microsoft dans les documents , ils utilisent uniquement les méthodes de contrôleur pour les réponses non par défaut comme NotFound
:
[HttpGet("{id}")]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult<Product> GetById(int id)
{
if (!_repository.TryGetProduct(id, out var product))
{
return NotFound();
}
return product;
}