web-dev-qa-db-fra.com

Puis-je écrire dans la console lors d'un test unitaire? Si oui, pourquoi la fenêtre de la console n'est pas ouverte?

J'ai un projet de test dans Visual Studio. J'utilise Microsoft.VisualStudio.TestTools.UnitTesting.

J'ajoute cette ligne dans l'un de mes tests unitaires:

Console.WriteLine("Some foo was very angry with boo");
Console.ReadLine();

Lorsque j'exécute le test, le test réussit, mais la fenêtre de la console n'est pas ouverte du tout.

Existe-t-il un moyen de rendre la fenêtre de console disponible pour l’interaction via un test unitaire?

109
pencilCake

REMARQUE: La réponse originale ci-dessous devrait fonctionner pour toutes les versions de VS jusqu'à VS2012. VS2013 ne semble plus avoir de fenêtre Résultats du test. Si vous avez besoin d'une sortie spécifique au test, vous pouvez utiliser la suggestion de Trace.Write() de @ Stretch pour écrire la sortie dans la fenêtre Sortie.


La méthode Console.Write n'écrit pas sur la "console" - elle écrit sur tout ce qui est connecté au handle de sortie standard du processus en cours d'exécution. De même, Console.Read lit les entrées à partir de tout ce qui est connecté à l'entrée standard.

Lorsque vous exécutez un test unitaire via VS2010, la sortie standard est redirigée par le faisceau de test et stockée avec la sortie de test. Vous pouvez le voir en cliquant avec le bouton droit de la souris sur la fenêtre Résultats du test et en ajoutant la colonne intitulée "Sortie (StdOut)" à l'écran. Cela montrera tout ce qui a été écrit sur stdout.

Vous pourriez ouvrir manuellement une fenêtre de console en utilisant P/Invoke comme @ sinni800 le dit. D'après la documentation AllocConsole, il apparaît que la fonction réinitialisera les poignées stdin et stdout pour qu'elles pointent vers la nouvelle fenêtre de la console. (Je ne suis pas tout à fait sûr à ce sujet; cela me semble un peu faux si j'ai déjà redirigé stdout pour que Windows me le vole, mais je n'ai pas essayé.)

En général, cependant, je pense que c'est une mauvaise idée. si vous souhaitez uniquement utiliser la console pour afficher davantage d'informations sur votre test unitaire, la sortie est là pour vous. Continuez à utiliser Console.WriteLine comme vous êtes et vérifiez les résultats dans la fenêtre Résultats du test lorsque vous avez terminé.

107
Michael Edenfield

Quelqu'un a commenté cette fonctionnalité apparemment nouvelle dans VS2013. Je ne savais pas trop ce qu'il voulait dire au début, mais maintenant que je le fais, je pense que cela mérite sa propre réponse.

Nous pouvons utiliser Console.WriteLine normalement et la sortie est affichée, mais pas dans la fenêtre de sortie, mais dans une nouvelle fenêtre après avoir cliqué sur "Sortie" dans les détails du test.

 enter image description here

133
Tiago Duarte

Vous pouvez utiliser cette ligne pour écrire dans Fenêtre de sortie de Visual Studio:

System.Diagnostics.Debug.WriteLine("Matrix has you...");

J'espère que cela pourra aider

28
Dmitry Pavlov

Comme indiqué, les tests unitaires sont conçus pour fonctionner sans interaction.

Cependant, vous pouvez déboguer des tests unitaires, comme n'importe quel autre code. Le moyen le plus simple consiste à utiliser le bouton Déboguer de l'onglet Résultats du test.

Être capable de déboguer signifie pouvoir utiliser les points d'arrêt. Pouvoir utiliser des points d'arrêt signifie donc pouvoir utiliser Tracepoints, que je trouve extrêmement utile dans le débogage quotidien.

Les points de trace vous permettent essentiellement d’écrire dans la fenêtre Sortie (ou, plus précisément, dans la sortie standard). Vous pouvez éventuellement continuer à courir ou vous arrêter comme un point d'arrêt habituel. Cela vous donne la "fonctionnalité" que vous demandez, sans qu'il soit nécessaire de reconstruire votre code ni de le remplir avec des informations de débogage.

Ajoutez simplement un point d'arrêt, puis cliquez avec le bouton droit de la souris sur ce point d'arrêt. Sélectionnez l'option "When Hit ...": When Hit option

Ce qui amène le dialogue: When Breakpoint Is Hit

Quelques points à noter:

  1. Notez que le point d'arrêt est maintenant affiché sous la forme d'un losange, au lieu d'une sphère, indiquant un point de trace. 
  2. Vous pouvez afficher la valeur d'une variable en l'enfermant comme ceci: {this}. 
  3. Décochez la case "Continuer l'exécution" pour que le code soit interrompu sur cette ligne, comme tout point d'arrêt habituel. 
  4. Vous avez la possibilité d'exécuter une macro. S'il vous plaît soyez prudent - vous pouvez provoquer des effets secondaires nocifs.

Voir la documentation pour plus de détails.

26
Wonko the Sane

Il existe plusieurs façons d'écrire la sortie d'un test d'unité Visual Studio en C #:

  • Console.Write - Le faisceau de test de Visual Studio va capturer cela et l'afficher lorsque vous sélectionnez le test dans l'explorateur de tests et cliquez sur le lien de sortie. Est-ce que not ne s'affiche pas dans la fenêtre de sortie de Visual Studio lors de l'exécution ou du débogage d'un test unitaire (il s'agit d'un bogue).
  • Debug.Write - Le harnais de test Visual Studio va capturer cela et l'afficher dans la sortie de test. Est-ce que apparaît dans la fenêtre de sortie de Visual Studio lors du débogage d'un test d'unité, sauf si les options de débogage de Visual Studio sont configurées pour rediriger la sortie vers la fenêtre Immédiate. Rien n'apparaîtra dans la fenêtre de sortie (ou immédiate) si vous exécutez simplement le test sans débogage. Par défaut, disponible uniquement dans une construction Debug (c'est-à-dire lorsque la constante DEBUG est définie).
  • Trace.Write - Le faisceau de test de Visual Studio va capturer cela et l'afficher dans la sortie de test. Est-ce que apparaît dans la fenêtre de sortie Visual Studio (ou Immediate) lors du débogage d'un test unitaire (mais pas lorsque vous exécutez simplement le test sans le débogage). Par défaut, disponible dans les versions Debug et Release (c'est-à-dire lorsque la constante TRACE est définie).

Confirmé dans Visual Studio 2013 Professional.

18
yoyo

Vous pouvez utiliser

Trace.WriteLine() 

pour écrire dans la fenêtre de sortie lors du débogage d’un unittest. 

5
Sturla

Dans Visual Studio 2017, "TestContext" n'indique pas le lien de sortie dans Test Explorer. Cependant, Trace.Writeline () affiche le lien Ouput. 

3
naz hassan

Tout d’abord, les tests unitaires sont, par design, supposés fonctionner complètement sans interaction.

Cela dit, je ne pense pas qu'il y ait une possibilité à laquelle on a pensé. 

Vous pouvez essayer le piratage avec AllocConsole P/Invoke qui ouvrira une console même si votre application actuelle est une application à interface graphique. La classe Console publiera ensuite sur la console maintenant ouverte.

2
sinni800

Ce n’est pas une solution, mais une approche du livre the 

art des tests unitaires par Roy Osherove

nous avons besoin de stubs pour rompre ces dépendances, comme écrire dans FileSystem ou écrire dans Event Log ou écrire dans la console - 

Le stub peut être passé dans la classe principale et si stub n'est pas nul, écrivez dans le stub. Cependant, il peut changer l’API (comme maintenant, le constructeur a un tronçon comme paramètre). L'autre approche consiste à hériter et à créer un objet fantaisie. qui est décrit ci-dessous.

    namespace ClassLibrary1
    {
       // TO BE TESTED
        public class MyBusinessClass
        {
            ConsoleStub myConsoleForTest;
            public MyBusinessClass()
            {
                // Constructor
            }

            // This is test stub approach - 2
            public MyBusinessClass(ConsoleStub console)
            {
                this.myConsoleForTest = console;
            }

            public virtual void MyBusinessMethod(string s)
            {
                // this needs to be unit tested
                Console.WriteLine(s);

                // Just an example - you need to be creative here
                // there are many ways 
                if (myConsoleForTest !=null){
                    myConsoleForTest.WriteLine(s);
                }
            }
        }

        public class ConsoleStub
        {
            private string textToBeWrittenInConsole;

            public string GetLastTextWrittenInConsole
            {
                get
                {
                    return this.textToBeWrittenInConsole;
                }
            }

            public void WriteLine(string text)
            {
                this.textToBeWrittenInConsole = text;
            }
        } 


        public class MyBusinessClassMock :MyBusinessClass
        {
            private ConsoleStub consoleStub;
            public MyBusinessClassMock()
            {
                // Constructor
            }

            public MyBusinessClassMock(ConsoleStub stub)
            {
                this.consoleStub = stub;
            }

            public override void MyBusinessMethod(string s)
            {
                // if MOCK is not an option then pass this stub 
                // as property or parameter in constructor 
                // if you do not want to change the api  still want
                // to pass in main class then , make it protected and 
                // then inherit it and make just a property for consoleStub

                base.MyBusinessMethod(s);
                this.consoleStub.WriteLine(s);
            }
        }

        [TestClass]
        public class ConsoleTest
        {
            private ConsoleStub consoleStub;
            private MyBusinessClassMock  mybusinessObj

            [TestInitialize]
            public void Initialize()
            {
               consoleStub = new ConsoleStub();
               mybusinessObj = new MyBusinessClassMock(consoleStub);
            }
            [TestMethod]
            public void TestMyBusinessMethod()
            {
                mybusinessObj.MyBusinessMethod("hello world");
                Assert.AreEqual(this.consoleStub.GetLastTextWrittenInConsole,"hello world" );
            }
        }

    }

// Approach - 2 
[TestClass]
    public class ConsoleTest
    {
        private ConsoleStub consoleStub;
        private MyBusinessClass  mybusinessObj

        [TestInitialize]
        public void Initialize()
        {
           consoleStub = new ConsoleStub();
           mybusinessObj = new MyBusinessClass(consoleStub);
        }
        [TestMethod]
        public void TestMyBusinessMethod()
        {
            mybusinessObj.MyBusinessMethod("hello world");
            Assert.AreEqual(this.consoleStub.GetLastTextWrittenInConsole,"hello world" );
        }
    }
1
dekdev

Debug.WriteLine () peut également être utilisé.

1
Jackie

Les messages de sortie IMHO ne sont pertinents que pour le scénario de test ayant échoué dans la plupart des cas. J'ai composé le format ci-dessous, vous pouvez créer le vôtre aussi. Ceci est affiché dans la fenêtre de VS Test Explorer elle-même. 

Comment afficher ce message dans la fenêtre de VS Test Explorer? Un exemple de code comme celui-ci devrait fonctionner.

if(test_condition_fails)
    Assert.Fail(@"Test Type: Positive/Negative.
                Mock Properties: someclass.propertyOne: True
                someclass.propertyTwo: True
                Test Properties: someclass.testPropertyOne: True
                someclass.testPropertyOne: False
                Reason for Failure: The Mail was not sent on Success Task completion.");

Vous pouvez avoir une classe séparée dédiée à cela pour vous. J'espère que ça aide!

0
DevCod

Visual Studio pour Mac

Aucune des autres solutions ne fonctionnait sur VS pour Mac

Si vous utilisez NUnit, vous pouvez ajouter un petit .NETprojet de console à votre solution, puis référencer le projet que vous souhaitez tester dans les références de cette nouvelle Projet de console.

Tout ce que vous faisiez dans vos méthodes [Test()] peut être fait dans la Main de l'application console de cette manière:

class MainClass
{
    public static void Main(string[] args)
    {
        Console.WriteLine("Console");

        // Reproduce the Unit Test
        var classToTest = new ClassToTest();
        var expected = 42;
        var actual = classToTest.MeaningOfLife();
        Console.WriteLine($"Pass: {expected.Equals(actual)}, expected={expected}, actual={actual}");
    }
}

Vous êtes libre d'utiliser Console.Write et Console.WriteLine dans votre code dans ces circonstances.

0
SwiftArchitect