Comment l'unité de test avec ILogger dans ASP.NET de Base
C'est mon contrôleur:
public class BlogController : Controller
{
private IDAO<Blog> _blogDAO;
private readonly ILogger<BlogController> _logger;
public BlogController(ILogger<BlogController> logger, IDAO<Blog> blogDAO)
{
this._blogDAO = blogDAO;
this._logger = logger;
}
public IActionResult Index()
{
var blogs = this._blogDAO.GetMany();
this._logger.LogInformation("Index page say hello", new object[0]);
return View(blogs);
}
}
Comme vous pouvez le voir j'ai 2 dépendances, un IDAO
et un ILogger
Et c'est ma classe de test, j'utilise xUnit de tester et de Moq de créer des maquettes et le talon, je peux maquette DAO
facile, mais avec le ILogger
je ne sais pas quoi faire donc je viens de passer la valeur null et commentez l'appel pour vous connecter au contrôleur pour lancer le test. Est-il un moyen de tester, mais encore de maintenir l'enregistreur en quelque sorte ?
public class BlogControllerTest
{
[Fact]
public void Index_ReturnAViewResult_WithAListOfBlog()
{
var mockRepo = new Mock<IDAO<Blog>>();
mockRepo.Setup(repo => repo.GetMany(null)).Returns(GetListBlog());
var controller = new BlogController(null,mockRepo.Object);
var result = controller.Index();
var viewResult = Assert.IsType<ViewResult>(result);
var model = Assert.IsAssignableFrom<IEnumerable<Blog>>(viewResult.ViewData.Model);
Assert.Equal(2, model.Count());
}
}
- Vous pouvez utiliser une maquette comme un tampon, comme Ilya suggère, si vous n'êtes pas réellement en train de tester la méthode de journalisation lui-même a été appelé. Si c'est le cas, se moquant de l'enregistreur ne fonctionne pas, et vous pouvez tenter quelques approches différentes. J'ai écrit un court article montrant une variété d'approches. L'article comprend complet d'un dépôt GitHub avec chacune des différentes options. En fin de compte, ma recommandation est d'utiliser votre propre carte plutôt que de travailler directement avec les ILogger<T> type, si vous avez besoin d'être en mesure de
- Comme @ssmith mentionné il y a quelques problèmes avec la vérification des appels réels pour
ILogger
. Il a quelques bonnes suggestions dans son article sur le blog et je suis venu avec ma solution qui semble résoudre la plupart des problèmes dans le réponse.
Vous devez vous connecter pour publier un commentaire.
Juste mock ainsi que de toute autre dépendance:
Vous aurez probablement besoin d'installer
Microsoft.Extensions.Logging.Abstractions
paquet utiliserILogger<T>
.En outre, vous pouvez créer un véritable enregistreur:
En fait, j'ai trouvé
Microsoft.Extensions.Logging.Abstractions.NullLogger<>
qui ressemble à une solution parfaite.services.AddSingleton<ILoggerFactory, NullLoggerFactory>();
et de créer des bûcherons, comme l'exige:var myLogger = loggerFactory.CreateLogger<...>();
public static ServiceCollection AddLogger(this ServiceCollection services) { var loggerFactory = NullLoggerFactory.Instance; loggerFactory.AddProvider(NullLoggerProvider.Instance); services.AddSingleton<ILoggerFactory>(loggerFactory); services.AddSingleton(typeof(ILogger<>), typeof(NullLogger<>)); return services; }
Utiliser un enregistreur de frappe qui utilise
ITestOutputHelper
(à partir de xunit) à la sortie de capture et de journaux. Voici un petit échantillon qui écrit seulement lesstate
à la sortie.L'utiliser dans votre unittests comme
Déjà mentionné, vous pouvez en moquer comme de toute autre interface.
So far So good.
Bonne chose est que vous pouvez utiliser
Moq
à vérifier que certains appels ont été effectués. Par exemple, ici je vérifie que le journal a été appelée avec un particulierException
.Lors de l'utilisation de
Verify
le point est de le faire à l'encontre de la véritableLog
méthode de laILooger
de l'interface et non pas les méthodes d'extension.Ajouter mes 2 cents, C'est une aide de la méthode d'extension généralement mis en statique de la classe helper:
Alors, vous l'utilisez comme ceci:
Et bien sûr, vous pouvez facilement étendre, à se moquer de toute attente (c'est à dire attente, message, etc ...)
Et lors de l'utilisation de StructureMap /Lamar:
Docs:
Il est facile que les autres réponses suggèrent de passer maquette
ILogger
, mais il devient d'un coup beaucoup plus problématique pour vérifier que les appels ont été effectivement faite à l'exploitant forestier. La raison en est que la plupart des appels ne lui appartiennent pas en propre à laILogger
interface elle-même.De sorte que la plupart des appels sont des méthodes d'extension qui appel la seule
Log
méthode de l'interface. La raison pour laquelle il me semble, c'est que c'est beaucoup plus facile de faire de la mise en œuvre de l'interface si vous avez un seul et pas beaucoup de surcharges qui se résume à la même méthode.L'inconvénient, c'est qu'il est tout à coup beaucoup plus difficile de vérifier qu'un appel a été fait depuis l'appel, vous devez vérifier est très différent de l'appel que vous faites. Il existe différentes approches pour contourner ce problème, et j'ai trouvé que la coutume des méthodes d'extension pour se moquant cadre de la rendre plus facile à écrire.
Voici un exemple d'une méthode que j'ai fait de travailler avec
NSubstitute
:Et c'est comment il peut être utilisé:
Il est exactement comme si vous avez utilisé la méthode directe, le truc c'est que notre méthode d'extension bénéficie d'une priorité parce que c'est "plus proche" dans les espaces de noms que l'original, de sorte qu'il sera utilisé à la place.
Il ne donne malheureusement à 100% de ce que nous voulons, à savoir les messages d'erreur ne sera pas aussi bon, étant donné que nous ne contrôle pas directement sur une chaîne, mais plutôt sur une lambda qui implique la chaîne, mais 95% est mieux que rien 🙂 en Outre, cette démarche permettra de faire le code de test
P. S. Pour Moq on peut utiliser l'approche de l'écriture d'une méthode d'extension pour le
Mock<ILogger<T>>
qui neVerify
pour obtenir des résultats similaires.