J'ai créé une API à l'aide d'ASP.NET MVC Core v2.1. Une de mes méthodes HttpGet
est configurée comme suit:
public async Task<IActionResult> GetConfiguration([FromRoute] int? id)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
..... // Some code here
return Ok(configuration);
}
catch (Exception ex)
{
... // Some code here
}
}
Lors des tests unitaires, je peux vérifier que Ok était la réponse, mais j'ai vraiment besoin de voir les valeurs de la configuration. Il semble que je ne sois pas capable de faire fonctionner ceci avec les éléments suivants:
[TestMethod]
public void ConfigurationSearchGetTest()
{
var context = GetContextWithData();
var controller = new ConfigurationSearchController(context);
var items = context.Configurations.Count();
var actionResult = controller.GetConfiguration(12);
Assert.IsTrue(true);
context.Dispose();
}
Au moment de l'exécution, je peux vérifier que actionResult
a certaines valeurs pour lesquelles je ne parviens pas à coder. Y a-t-il quelque chose que je fais mal? Ou suis-je simplement en train de penser à cela? J'aimerais pouvoir faire:
Assert.AreEqual(12, actionResult.Values.ConfigurationId);
Les bonnes pratiques suggèrent de ne pas avoir beaucoup de code dans les actions de votre contrôleur à tester et que la majeure partie de la logique se trouve dans des objets découplés ailleurs qui sont beaucoup plus faciles à tester. Cela dit, si vous souhaitez toujours tester vos contrôleurs, vous devez effectuer votre test async
et attendre les appels.
L’un des problèmes que vous aurez, c’est que vous utilisez IActionResult
car cela vous permet de renvoyer BadRequest(...)
et Ok(...)
. Cependant, étant donné que vous utilisez ASP.NET MVC Core 2.1, vous souhaiterez peut-être commencer par utiliser le nouveau type ActionResult<T>
. Cela devrait vous aider dans vos tests car vous pouvez désormais accéder directement à la valeur de retour fortement typée. Par exemple:
//Assuming your return type is `Configuration`
public async Task<ActionResult<Configuration>> GetConfiguration([FromRoute] int? id)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
..... // Some code here
// Note we are now returning the object directly, there is an implicit conversion
// done for you
return configuration;
}
catch (Exception ex)
{
... // Some code here
}
}
Notez que nous retournons maintenant l'objet directement car il existe une conversion implicite de Foo
à ActionResult<Foo>
Votre test peut maintenant ressembler à ceci:
[TestMethod]
public async Task ConfigurationSearchGetTest()
{
var context = GetContextWithData();
var controller = new ConfigurationSearchController(context);
var items = context.Configurations.Count();
// We now await the call
var actionResult = await controller.GetConfiguration(12);
// And the value we want is now a property of the return
var configuration = actionResult.Value;
Assert.IsTrue(true);
context.Dispose();
}
Vous devez attendre l'appel de GetConfiguration pour récupérer l'objet IActionResult comme suit:
var actionResult = await controller.GetConfiguration(12);
Pour ce faire, vous devez également modifier la signature de votre méthode de test de manière asynchrone. Alors changez ceci:
public void ConfigurationSearchGetTest()
Pour ça:
public async Task ConfigurationSearchGetTest()
Comme ma réputation ne me permet pas de commenter la réponse de @DavidG, qui va dans la bonne direction, je vais vous donner un exemple pour obtenir la valeur dans Task .
Comme @ Christopher J. Reynolds l'a fait remarquer actionResult.Value peut être vu à runtime mais pas dans le temps de compilation .
Donc, je vais montrer un test de base dans lequel obtenir les valeurs:
[TestMethod]
public async Task Get_ReturnsAnArea()
{
// Arrange
string areaId = "SomeArea";
Area expectedArea = new Area() { ObjectId = areaId, AreaNameEn = "TestArea" };
var restClient = new Mock<IRestClient>();
restClient.Setup(client => client.GetAsync<Area>(It.IsAny<string>(), false)).ReturnsAsync(expectedArea);
var controller = new AreasController(restClient.Object);
//// Act
// We now await the call
IActionResult actionResult = await controller.Get(areaId);
// We Cast it to the expected Response Type
OkObjectResult okResult = actionResult as OkObjectResult;
// Assert
Assert.IsNotNull(okResult);
Assert.AreEqual(200, okResult.StatusCode);
Assert.AreEqual(expectedArea, okResult.Value);
//We Cast Value to the expected Type
Area actualArea = okResult.Value as Area;
Assert.IsTrue(expectedArea.AreaNameEn.Equals(actualArea.AreaNameEn));
}
Bien sûr, cela pourrait être amélioré, mais je voulais juste vous montrer un moyen simple de le comprendre. J'espère que cela vous aidera.
Vous pouvez obtenir un contrôleur testé sans changer le type renvoyé.IActionResult
est le type de base pour tous les autres.
Convertit le résultat dans le type attendu et compare la valeur renvoyée à la valeur attendue.
Puisque vous testez une méthode asynchrone, rendez-la également asynchrone.
[TestMethod]
public async Task ConfigurationSearchGetTest()
{
using (var context = GetContextWithData())
{
var controller = new ConfigurationSearchController(context);
var items = context.Configurations.Count();
var actionResult = await controller.GetConfiguration(12);
var okResult = actionResult as OkObjectResult;
var actualConfiguration = okResult.Value as Configuration:
// Now you can compare with expected values
actualConfuguration.Should().BeEquivalentTo(expected);
}
}