【问题标题】:Resharper test runner not outputting Console.WriteLine()?Resharper 测试运行器不输出 Console.WriteLine()?
【发布时间】:2017-11-13 19:38:14
【问题描述】:

为什么Console.Writeline() 在从控制台应用程序main() 方法执行时会起作用;但是当我使用 resharpers 测试运行器执行相同操作时,我在测试运行器输出窗口中看不到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() 调用显示字符串。但我没有。例如这里是一个截图:

现在让我们执行完全相同的序列,但这次我们将从新的控制台项目 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();
        }
    }
}

接下来执行控制台应用程序。您应该会看到以下显示:

谁能解释我如何配置我的代码或测试运行器以在测试运行器输出窗口中显示输出?

* 更新 * 我取得了部分成功。 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 状态。看起来像这样:

简短的故事:我仍在寻找解决方案。

*** 解决方案 ****

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

【问题讨论】:

  • 向用户界面输出信息是否违背了单元测试的目的?是什么让测试成功或失败?输出到控制台的内容如何影响该决定?
  • 如果它用于调试目的,那么您应该使用System.Diagnostics.Debug 和您选择的TraceListener
  • @InBetween:我正在为一个负责编写单元测试断言方法的同事设置这个示例。在输出窗口中编写一些有用的 console.writeline() 并没有错。它可以帮助我的同事“一目了然”地看到状态。

标签: c# unit-testing resharper


【解决方案1】:

看起来 Resharper 在您的线程完成之前就完成了。您的来电

Thread(Run).Start();

是非阻塞的。这意味着测试线程将在 Go 线程之前完成,因此您不会得到任何结果。

参见https://msdn.microsoft.com/en-us/library/6x4c42hc(v=vs.110).aspx where is states “注意,对 Start 的调用不会阻塞调用线程。”

【讨论】:

  • 谢谢。那成功了。在我的单元测试中,我添加了 Thread.Sleep(1000);并且能够看到输出。
  • 另外,不需要 TraceListener 等。我只能使用 Console.WriteLine() 和 Thread.Sleep() 来达到预期的结果。
  • 干得好,尽管我建议您避免在测试中休眠,因为这会增加不必要的延迟并引入您所经历的竞争条件。在这种情况下,一个更好的选择是使用此答案中的一个选项:stackoverflow.com/questions/1584062/…
猜你喜欢
  • 2012-10-18
  • 2016-04-18
  • 1970-01-01
  • 2010-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-12
  • 2014-01-03
相关资源
最近更新 更多