web-dev-qa-db-ja.com

単体テストでコンソールに書き込むことはできますか?はいの場合、コンソールウィンドウが開かないのはなぜですか?

Visual Studioにテストプロジェクトがあります。 Microsoft.VisualStudio.TestTools.UnitTestingを使用します。

ユニットテストの1つにこの行を追加します。

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

テストを実行すると、テストは成功しますが、コンソールウィンドウはまったく開かれません。

単体テストでコンソールウィンドウを操作できるようにする方法はありますか?

112
pencilCake

注:以下の元の回答は、VS2012までのVSのすべてのバージョンで機能するはずです。 VS2013には、[テスト結果]ウィンドウが表示されなくなりました。代わりに、テスト固有の出力が必要な場合は、@ StretchのTrace.Write()の提案を使用して、出力ウィンドウに出力を書き込むことができます。


Console.Writeメソッドは「コンソール」に書き込みません。実行中のプロセスの標準出力ハンドルに接続されているものに書き込みます。同様に、Console.Readは、標準入力に接続されているものから入力を読み取ります。

VS2010を通じて単体テストを実行すると、標準出力はテストハーネスによってリダイレクトされ、テスト出力の一部として保存されます。これを確認するには、テスト結果ウィンドウを右クリックし、「出力(StdOut)」という名前の列を表示に追加します。これにより、stdoutに書き込まれたものがすべて表示されます。

could @ sinni800が言うようにP/Invokeを使用して、手動でコンソールウィンドウを開きます。 AllocConsolename__のドキュメントを読むと、この関数はstdinname__およびstdoutname__ハンドルをリセットして新しいコンソールウィンドウを指すように見えます。 (私はそれについて100%確信していません;それを盗むためにWindows用にstdoutname__をすでにリダイレクトしている場合、それはちょっと間違っているようですが、私は試していません。)

しかし、一般的には、それは悪い考えだと思います。コンソールを使用したいのがユニットテストに関する詳細情報をダンプすることだけである場合、出力はそこにあります。 Console.WriteLineをそのまま使用し、完了したら、[テスト結果]ウィンドウで出力結果を確認します。

110

VS2013のこの明らかに新しい機能について誰かがコメントしました。私は彼が最初は何を意味したのか確信が持てませんでしたが、今私はそうしているので、それは自分の答えに値すると思います。

Console.WriteLineを通常どおり使用することができ、出力は単に[出力]ウィンドウではなく、テストの詳細で[出力]をクリックした後の新しいウィンドウに表示されます。

enter image description here

145
Tiago Duarte

この行を使用して、Visual Studioの 出力ウィンドウ に書き込むことができます。

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

役立つことを願っています

32
Dmitry Pavlov

前述のように、単体テストは相互作用なしで実行されるように設計されています。

ただし、他のコードと同様に、単体テストをデバッグできます。最も簡単な方法は、[テスト結果]タブの[デバッグ]ボタンを使用することです。

デバッグできるとは、ブレークポイントを使用できることを意味します。したがって、ブレークポイントを使用できるということは、Tracepointsを使用できることを意味します。これは、毎日のデバッグに非常に役立ちます。

基本的に、トレースポイントを使用すると、出力ウィンドウ(または、より正確には標準出力)に書き込むことができます。オプションで、実行を継続することも、通常のブレークポイントのように停止することもできます。これにより、コードを再構築したり、デバッグ情報で埋めたりすることなく、求めている「機能」が得られます。

単にブレークポイントを追加し、そのブレークポイントを右クリックします。 [ヒット時...]オプションを選択します。 When Hit option

ダイアログが表示されます: When Breakpoint Is Hit

注意すべきいくつかの点:

  1. ブレークポイントが、球ではなくひし形で表示され、トレースポイントを示していることに注意してください。
  2. {this}のように変数を囲むことにより、変数の値を出力できます。
  3. 「継続実行」チェックボックスをオフにして、通常のブレークポイントと同様に、この行でコードを中断します。
  4. マクロを実行するオプションがあります。注意してください-有害な副作用を引き起こす可能性があります。

詳細については、ドキュメントを参照してください。

27
Wonko the Sane

C#でVisual Studio単体テストからの出力を書き込む方法はいくつかあります。

  • Console.Write-Visual Studioテストハーネスはこれをキャプチャし、テストエクスプローラーでテストを選択して[出力]リンクをクリックすると表示されます。 notは、単体テストを実行またはデバッグするときにVisual Studioの出力ウィンドウに表示されます(おそらくこれはバグです)。
  • Debug.Write-Visual Studioテストハーネスはこれをキャプチャし、テスト出力に表示します。 Doesユニットテストのデバッグ時に、Visual Studioのデバッグオプションがイミディエイトウィンドウにリダイレクトするように構成されていない限り、Visual Studioの出力ウィンドウに表示されます。デバッグせずにテストを実行するだけでは、出力(またはイミディエイト)ウィンドウには何も表示されません。デフォルトでは、デバッグビルドでのみ使用可能です(つまり、DEBUG定数が定義されている場合)。
  • Trace.Write-Visual Studioテストハーネスはこれをキャプチャし、テスト出力に表示します。 Doesは、単体テストのデバッグ時にVisual Studio出力(またはイミディエイト)ウィンドウに表示されます(ただし、デバッグなしでテストを実行するだけではありません)。デフォルトでは、デバッグビルドとリリースビルドの両方で使用可能です(つまり、TRACE定数が定義されている場合)。

Visual Studio 2013 Professionalで確認済み。

19
yoyo

使用できます

Trace.WriteLine() 

unittestのデバッグ時に出力ウィンドウに書き込む。

6
Sturla

Visual Studio 2017では、「TestContext」はテストエクスプローラーに出力リンクを表示しません。ただし、Trace.Writeline()はOuputリンクを示しています。

4
naz hassan

すべてのユニットテストの最初は、designによって、相互作用なしで完全に実行されることになっています。

それはさておき、私は考えられていた可能性があるとは思わない。

AllocConsole P/Invoke を使用してハッキングを試みると、現在のアプリケーションがGUIアプリケーションであってもコンソールが開きます。 Consoleクラスは、現在開かれているコンソールにポストします。

3
sinni800

Debug.WriteLine()も使用できます。

3
Jackie

これはまさに解決策ではなく、本からのアプローチです

roy Osheroveによるユニットテストの芸術

fileSystemへの書き込み、イベントログへの書き込み、コンソールへの書き込みなど、これらの依存関係を解消するためのスタブが必要です-

スタブはメインクラスに渡され、スタブがnullでない場合はスタブに書き込みます。ただし、APIを変更できます(コンストラクターがパラメーターとしてスタブを持つようになりました)。もう1つのアプローチは、モックオブジェクトの継承と作成です。以下で説明します。

    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" );
        }
    }
2
dekdev

IMHO出力メッセージは、ほとんどの場合、失敗したテストケースにのみ関連します。以下の形式を作成しましたが、独自の形式も作成できます。これは、VS Test Explorerウィンドウ自体に表示されます。

VS Test Explorerウィンドウでこのメッセージをスローする方法は?このようなサンプルコードが機能するはずです。

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.");

これ専用の個別のクラスを用意できます。それが役に立てば幸い!

2
DevCod

Visual Studio For Mac

他のソリューションのどれもVS for Macで動作しませんでした

NUnitを使用している場合、小さな.NETConsole Projectをソリューションに追加し、テストするプロジェクトをReferencesで参照できます。その新しいConsole Projectの。

[Test()]メソッドで実行していたことはすべて、この方法でコンソールアプリのMainで実行できます。

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}");
    }
}

これらの状況では、コードでConsole.WriteおよびConsole.WriteLineを自由に使用できます。

1
SwiftArchitect