ReSharper测试运行器为什么没有输出Console.WriteLine()?

5
为什么在从控制台应用程序的main()方法执行时,Console.Writeline()可以正常工作;但是当我使用resharpers测试运行器执行相同的操作时,我看不到Console.Writeline()在测试运行器输出窗口中的输出?
最好的方法是通过一个例子来解释。
我正在使用:Resharper Ultimate 2017.1.3、Visual Studio 2017 Community和.Net 4.6.1框架。语言是C#。我还安装了(通过nuget)nunit framework 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

请问有人能解释一下我如何配置我的代码或测试运行器以在测试运行器输出窗口中显示输出吗?
*更新* 我取得了部分成功。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();
        }
    }

结果令人惊讶:我确实得到了一些输出;但只有初始的BEGIN状态。它看起来像这样:

enter image description here

翻译:短故事:我仍在寻找解决方案。

***解决方案***

        [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.
        }

将信息输出到用户界面不是违背单元测试的目的吗?是什么决定了测试的成功或失败,控制台输出的内容如何影响这个决定? - InBetween
1
如果是为了调试目的,那么你应该使用 System.Diagnostics.Debug 和你选择的 TraceListener - InBetween
1
@InBetween:我正在为一个同事设置这个示例,他的工作将是编写单元测试断言方法。在输出窗口中编写一些有用的console.writeline()没有任何问题。它可以帮助我的同事一目了然地看到状态。 - sapbucket
1个回答

2

看起来Resharper在你的线程完成之前就已经结束了。你调用的

Thread(Run).Start();

是非阻塞的。这意味着测试线程将在 Go 线程之前完成,因此您将获得没有结果。

请参见 https://msdn.microsoft.com/en-us/library/6x4c42hc(v=vs.110).aspx,其中指出“注意,调用 Start 并不会阻止调用线程。”


谢谢。那个方法很有效。在我的单元测试中,我添加了Thread.Sleep(1000); 然后就能够看到输出结果了。 - sapbucket
此外,并不需要使用 TraceListener 等组件。仅凭 Console.WriteLine() 和 Thread.Sleep() 就可以实现所需的结果。 - sapbucket
1
做得好,虽然我鼓励你在测试中避免使用sleep,因为这会增加不必要的延迟并引入竞争条件,就像你所经历的那样。在这种情况下,更好的选择是使用此答案中的选项之一:https://dev59.com/HXI-5IYBdhLWcg3w-9wK。 - Stephen Straton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接