5

Why is it that Console.Writeline() will work when executing from a console app main() method; but when I execute the same using resharpers test runner I do not see the Console.Writeline() in the test runner output window?

The best way to explain this is with an example.

I am using: Resharper Ultimate 2017.1.3, Visual Studio 2017 Community, and .Net 4.6.1 framework. Language is C#. I also installed (via nuget) nunit framework 2.6.4.

First create a class library and copy paste the following in to a .cs file.

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

And now execute the test. I expect to see the Console.WriteLine() calls display strings in the Resharper test runner output window. But I don't. For example here is a screenshot:

enter image description here

Now let's perform the exact same sequence, but this time we'll call the client code from a new console project main() method. To set this up copy paste the following code and reference the class library you created in the steps above.

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

Next execute the console app. You should see the following displayed:

enter image description here

Can anyone please explain how I can configure either my code or the test runner to display the output in the test runner output window?

* UPDATE * I made partial success. InBetween's suggestion to use a TraceListener made me realize I should be using a ConsoleTraceListener. To faciliate this I modified the unit test to appear like this:

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

And the results are surprising: I do get SOME output; but only the initial BEGIN state. Which appears like this:

enter image description here

Short story: I'm still looking for a solution.

*** 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.
        }
sapbucket
  • 6,795
  • 15
  • 57
  • 94
  • Doesn't outputting info to a user interface defeat the purpose of a unit test? What makes the test succeed or fail and how does whatever is outputted to the console come into play in that decision? – InBetween Nov 13 '17 at 20:49
  • 1
    If its for debugging purposes then you should be using `System.Diagnostics.Debug` and the `TraceListener` of your choice. – InBetween Nov 13 '17 at 20:59
  • 1
    @InBetween: I'm setting this example up for a coworkers whos job will be to write the unit test assert methods. There is nothing wrong with writing some helpful console.writeline() in the output window. It helps my coworker see the state "at a glance". – sapbucket Nov 14 '17 at 00:05

1 Answers1

2

It looks like Resharper is finishing before your thread completes. Your call to

Thread(Run).Start();

is non-blocking. This means the test thread will complete before the Go thread does, hence you get no results.

See https://msdn.microsoft.com/en-us/library/6x4c42hc(v=vs.110).aspx where is states "Note that the call to Start does not block the calling thread."

Stephen Straton
  • 709
  • 5
  • 12
  • thank you. that did the trick. In my unit test I added Thread.Sleep(1000); and was able to see the output. – sapbucket Nov 15 '17 at 16:48
  • Also, there was no need for a TraceListener, etc. I was able to achieve the desired results using Console.WriteLine() and Thread.Sleep(), only. – sapbucket Nov 15 '17 at 16:53
  • 1
    Well done, although I would encourage you to avoid sleeps in tests as these will add unnecessary delays and introduce race conditions like you experienced. A preferable option in this case would be to use one of the options in this answer: https://stackoverflow.com/questions/1584062/how-to-wait-for-thread-to-finish-with-net. – Stephen Straton Nov 15 '17 at 23:10