2017-11-13 6 views
0

コンソールアプリケーションから実行するとConsole.Writeline()が動作するのはなぜですかmain()メソッドです。私がresharpersテストランナーを使って同じものを実行すると、テストランナー出力ウィンドウにConsole.Writeline()が表示されませんか?ResharperテストランナーはConsole.WriteLine()を出力していませんか?

これを説明する最善の方法は例です。

Resharper Ultimate 2017.1.3、Visual Studio 2017 Community、.Net 4.6.1フレームワークを使用しています。言語はC#です。私も(nuget経由で)nunitフレームワーク2.6.4をインストールしました。

最初にクラスライブラリを作成し、以下を.csファイルに貼り付けてコピーします。

using System; 
using System.Collections; 
using System.Threading; 
using NUnit.Framework; 

namespace ObserverPatternExample 
{ 
    [TestFixture] 
    internal class ObserverTestFixture 
    { 
     [Test] 
     public void DemonstrateObserverPattern() 
     { 
      var subject = new Subject(); 
      var a = new Observer(subject, "a"); 
      var b = new Observer(subject, "b"); // etc. as many observers as you want. 

      subject.Go(); 
     } 
    } 

    // "subject" is observer pattern lingo. The "subject" will do the broadcasting to the observers. 
    public class Subject 
    { 
     public delegate void CallbackHandler(string s); 
     public event CallbackHandler NotifyEvent; 
     private const int waitTimeInMilliseconds = 200; 
     private readonly Simulator simulator = new Simulator(); 
     public string FakeSimulatorState { get; set; } 

     public void Go() 
     { 
      new Thread(Run).Start(); // a good thing to notice: events cross thread boundaries!!! 
     } 

     private void Run() 
     { 
      foreach (string s in simulator) 
      { 
       Console.WriteLine("Subject: " + s); 
       FakeSimulatorState = s; 
       NotifyEvent?.Invoke(s); 
       Thread.Sleep(
        waitTimeInMilliseconds); // we do this to "pretend" that the simulator is actually doing someting. 
      } 
     } 


    } 

    public class Observer : IObserverPattern // the "observer" will subscribe to the event being broadcast by the "subject" 
    { 
     private readonly string _name; 
     public Observer(Subject subject, string name) 
     { 
      _name = name; 
      subject.NotifyEvent += Update; 
     } 
     public void Update(string state) 
     { 
      Console.WriteLine("Observer {0}: {1}", _name, state); 
     } 
    } 

    internal interface IObserverPattern 
    { 
     void Update(string state); 
    } 

    public class Simulator : IEnumerable 
    { 
     private readonly string[] _stateSequence = { "BEGIN", "CRAWL", "WALK", "JUMP", "END" }; 

     public IEnumerator GetEnumerator() 
     { 
      foreach (var s in _stateSequence) 
       yield return s; 
     } 
    } 
} 

これでテストが実行されます。 Resharperテストランナーの出力ウィンドウにConsole.WriteLine()呼び出しが文字列を表示することが期待されます。しかし、私はしません。例えば、ここにスクリーンショットです:

enter image description here

今度は、まったく同じシーケンスを実行できますが、今回は新しいコンソールプロジェクトのmain()メソッドからクライアントコードを呼ぶことにします。これを設定するには、次のコードを貼り付け、上記の手順で作成したクラスライブラリを参照します。

using ObserverPatternExample; 

namespace ConsoleApp1 
{ 
    internal class Program 
    { 
     private static void Main(string[] args) 
     { 
      var subject = new Subject(); 
      var a = new Observer(subject, "a"); 
      var b = new Observer(subject, "b"); // etc. as many observers as you want. 

      subject.Go(); 
     } 
    } 
} 

次に、コンソールアプリケーションを実行します。あなたは、次の表示されるはずです。

enter image description here

を誰もがテストランナーの出力ウィンドウに出力を表示するために、私は設定することができますどのように私のコードやテストランナーのどちらかを説明していただけますか?

* UPDATE * 部分的に成功しました。 InBetweenの提案でTraceListenerを使用すると、ConsoleTraceListenerを使用する必要があることが分かりました。

using System.Threading; 
using NUnit.Framework; 

namespace ObserverPatternExample.DontUse 
{ 
    [TestFixture] 
    internal class ObserverTestFixture 
    { 
     [SetUp] 
     public void Setup() 
     { 
      Trace.Listeners.Add(new ConsoleTraceListener()); 
     } 

     [TearDown] 
     public void TearDown() 
     { 
      Trace.Flush(); 
     } 

     [Test] 
     public void DemonstrateObserverPattern() 
     { 
      var subject = new Subject(); 
      var a = new Observer(subject, "a"); 
      var b = new Observer(subject, "b"); // etc. as many observers as you want. 

      subject.Go(); 
     } 
    } 

、その結果は驚くべきものである:これをfaciliateするために、私はこのように表示されるようにユニットテストを修正私はいくつかの出力を得るのです。初期のBEGIN状態のみになります。これは次のように表示されます

enter image description here

ショートストーリー:私はまだ解決策を探しています。

*** SOLUTION ****

 [Test] 
     public void DemonstrateObserverPattern() 
     { 
      var subject = new Subject(); 
      var a = new Observer(subject, "a"); 
      var b = new Observer(subject, "b"); // etc. as many observers as you want. 

      subject.Go(); 

Thread.Sleep(1000); // <--- add this to force test runner to wait for other thread to complete. 
     } 
+0

ユーザーインターフェイスに情報を出力しないと、単体テストの目的が無効になりますか?テストが成功するか失敗するか、コンソールに出力されたものはどのようにその決定に影響を与えますか? – InBetween

+0

デバッグのために 'System.Diagnostics.Debug'と' TraceListener'を使用する必要があります。 – InBetween

+0

@InBetween:ユニットテストアサートメソッドを書く仕事をする同僚のためのこの例を設定します。有用なconsole.writeline()を出力ウィンドウに書くことに何も問題はありません。それは私の同僚が "一目で"状態を見るのを助ける。 – sapbucket

答えて

2

あなたのスレッドが完了する前にReSharperの仕上げされたように見えます。

Thread(Run).Start(); 

へのあなたの電話は非ブロッキングです。つまり、Goスレッドが行う前にテストスレッドが完了するため、結果は得られません。

https://msdn.microsoft.com/en-us/library/6x4c42hc(v=vs.110).aspxを参照してください。状態は「開始への呼び出しが呼び出しスレッドをブロックしないことに注意してください。

+0

ありがとうございます。そのトリックをした。私のユニットテストでは、Thread.Sleep(1000)を追加しました。出力を見ることができました。 – sapbucket

+0

また、TraceListenerなどは必要ありませんでした。Console.WriteLine()とThread.Sleep()を使用して目的の結果を得ることができました。 – sapbucket

+1

よくできていますが、テストで睡眠を避けることをお勧めしますが、これは不必要な遅延を招き、経験したような競争条件を導入するためです。この場合の好ましいオプションは、この回答のオプションの1つ、つまりhttps://stackoverflow.com/questions/1584062/how-to-wait-for-thread-to-finish-with-netを使用することです。 –

関連する問題