xUnit.net ne capture pas la sortie de la console

Je viens de commencer à tester xUnit.net, mais il ne semble pas capturer de sortie (Console, Debug, Trace), comme je l'aurais prévu.

Est-ce possible? J'utilise un exemple de bibliothèque de classes. net 4.0 avec xUnit.net 1.8.

26
demandé sur Peter Mortensen 2011-08-21 18:42:44

5 réponses

En général, c'est une mauvaise route à suivre pour dépendre des tests de journalisation et. Le succès / échec devrait être le résultat des tests. Et ils ne devraient tout simplement pas arriver à l'étape où il y a assez de choses qui se passent pour regarder une trace sera nécessaire.

Le xunit.gui.exe affiche la sortie Console et Trace, xunit.console.exe ne le fait pas. Si c'est important, vous pouvez connecter un TraceListener qui redirige vers un fichier en créant des entrées de configuration. net standard appropriées (il y a un FileWriterTraceListener que vous devriez être en mesure de se connecter si vous google il).


Mise à jour: comme discuté dans son billet de blog , Damian Hickey a un bon exemple d'un possible remplacement - câblage logging à la xUnit 2 ITestOutputHelper comme démontré dans https://github.com/damianh/CapturingLogOutputWithXunit2AndParallelTests/blob/master/src/Lib.Tests/Tests.cs

Mise à jour 2: Dans certains cas, on peut ajouter la journalisation et l'alimenter au ITestOutputHelper sans impliquer LogContext en utilisant un adaptateur simple comme suit (je n'ai il en F#, désolé):

// Requirement: Make SUT depend on Serilog NuGet
// Requirement: Make Tests depend on Serilog.Sinks.Observable

type TestOutputAdapter(testOutput : Xunit.Abstractions.ITestOutputHelper) =
    let formatter = Serilog.Formatting.Display.MessageTemplateTextFormatter(
        "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] {Message}{NewLine}{Exception}", null);
    let write logEvent =
        use writer = new System.IO.StringWriter()
        formatter.Format(logEvent, writer);
        writer |> string |> testOutput.WriteLine
    member __.Subscribe(source: IObservable<Serilog.Events.LogEvent>) =
        source.Subscribe write

let createLogger hookObservers =
    LoggerConfiguration()
        .WriteTo.Observers(Action<_> hookObservers)
        .CreateLogger()
let createTestOutputLogger (output: ITestOutputHelper) =
    let adapter = TestOutputAdapter testOutputHelper
    createLogger (adapter.Subscribe >> ignore)

type Tests(testOutputHelper) =
    let log = createTestOutputLogger testOutputHelper

    [<Fact>] let feedToSut () =
        // TODO pass log to System Under Test either as a ctor arg or a method arg

La différence avec cette approche par rapport à l'utilisation du contexte de journal est que la journalisation dans le Serilog global [contextualisé] Logger ne sera pas récupérée.

3
répondu Ruben Bartelink 2017-09-01 22:00:42

La situation a un peu changé avec xUnit.net 2. Je sais que la question concerne une version antérieure, mais comme les gens atterriront ici après avoir effectué la mise à niveau, j'ai pensé que cela valait la peine de le souligner.

Pour voir une sorte de sortie dans la sortie de test dans la version 2, vous devrez prendre une dépendance dans votre classe de test (via un argument constructeur) sur une instance de ITestOutputHelper, puis utiliser la méthode WriteLine sur cette interface. Par exemple:

public class MyTestSpec
{
  private readonly ITestOutputHelper _testOutputHelper;

  public MyTestSpec(ITestOutputHelper testOutputHelper)
  {
    _testOutputHelper = testOutputHelper;
  }

  [Fact]
  public void MyFact()
  {
    _testOutputHelper.WriteLine("Hello world");
  }
}

Vous pouvez choisir de brancher votre logging framework à cette interface, peut-être en injectant une implémentation ILog qui a transmis tous les appels à ITestOutpuHelper.

Je reconnais que vous ne voudrez pas le faire par défaut, mais à des fins de diagnostic de temps en temps, cela peut être très utile. Cela est particulièrement vrai lorsque vos tests échouent uniquement sur certains serveurs de test et de construction basés sur le cloud!

34
répondu Josh Gallagher 2015-06-25 16:06:31

Cela peut aider si votre Console.Write est intégré au fond d'une hiérarchie de classes que vous ne voulez pas refactoriser:

    public MyTestClass(ITestOutputHelper output)
    {
        var converter = new Converter(output);
        Console.SetOut(converter);
    }

    private class Converter : TextWriter
    {
        ITestOutputHelper _output;
        public Converter(ITestOutputHelper output)
        {
            _output = output;
        }
        public override Encoding Encoding
        {
            get { return Encoding.Whatever; }
        }
        public override void WriteLine(string message)
        {
            _output.WriteLine(message);
        }
        public override void WriteLine(string format, params object[] args)
        {
            _output.WriteLine(format, args);
        }
    }
3
répondu Benjol 2017-11-28 10:34:15

Il y a une solution trouvée ici: https://xunit.codeplex.com/discussions/211566

Ajoutez simplement ceci à votre constructeur ou méthode où vous voulez la sortie de débogage:

Debug.Listeners.Add(new DefaultTraceListener());
2
répondu pixelshaded 2013-04-18 22:38:50

, Il peut être utile de partager mon expérience ici:

Dans un nouveau projet (avec des bibliothèques héritées), j'ai essayé xUnit. Il est célèbre et même l'équipe de langue C# l'utiliser, il doit donc être cool. Et j'ai frappé le problème de sortie de la console très rapidement. Au départ, j'étais très confus pourquoi je n'avais pas de sorties de console. Ils ont très bien fonctionné à NUnit ou MSTest.

J'ai lu bien que xUnit docs, et trouvé que ses auteurs ont une opinion forte: la sortie de la console dans les tests est mauvaise. OK. Je vois leur point, mais je ne pas entièrement d'accord, en particulier dans de nombreux projets concrets qui sont souvent un mélange d'héritage et hacks. Heureusement, ils ont fourni la solution ITestOutputHelper, ou une solution de contournement? C'est une passe-partout à écrire, mais OK, je les ai écrits.

J'ai ensuite eu une sortie, ehh... Qu'en est-il des autres? Oh oui, le code d'installation unique, qui était maintenant dans class fixtures. J'ai donc également injecté ITestOutputHelper là-bas, et j'ai couru. Et j'ai eu une erreur, il ne peut pas instancier la classe fixture. Donc, ITestOutputHelper n'est pas supporté là-bas.

Hmm... Je peut mettre en cache la sortie de phase d'installation et les écrire dans les tests plus tard, mais ils seront sortis une fois par test. Je peux écrire une fonction pour utiliser un drapeau de variable statique, de manière à n'écrire qu'une seule fois, mais il s'affiche comme la sortie du 1er test, au lieu du niveau d'assemblage. Donc un peu aléatoire, difficile à trouver. Et le pire problème est, la sortie de la console de un temps d'abattre n'a pas de sortie.

O...K... Permettez-moi de le laisser pour l'instant. Et j'ai continué mon voyage. Puis j'ai fait face à quelques teste les cas qui nécessitent un ordre d'exécution dédié. Ouais, je sais que c'est pas cool. Mais il y a des cas, en particulier dans certains tests d'intégration, c'est le moyen le plus simple et le plus naturel de le faire. Cela peut être aussi simple que d'ajouter un attribut [Order()] dans NUnit, ou de créer un test ordonné dans MSTest. Mais je suis allé bien que les docs xUnit, seulement pour le trouver non pris en charge, même si les docs fournissent un exemple de code de projet pour étendre et ajouter cette fonctionnalité.

Donc, contrairement à NUnit / MSTest, xUnit est un avis outil. Cela rend délibérément difficile de faire de mauvaises choses (selon ses auteurs). Si vous trouvez dans le besoin de fonctionnalités xUnit ne fournit pas, comme moi, il n'est pas le bon outil pour vous.

0
répondu Dudu 2018-06-03 14:27:18