2

This is a follow up from Grabbing the output sent to Console.Out from within a unit test? and the referenced article in the accepted answer by Mark Seemann.

I would like to use Console.Out and Console.In to redirect the streams while testing. Every test in the class needs to use the redirects.

In order to keep the tests clean I would like to do this in the test SetUp and TearDown.

This is what I was thinking:

private StringWriter _sw;
private StringReader _sr;
[SetUp]
public void SetUp()
{
    _sw = new StringWriter();
    Console.SetOut(_sw);
    _sr = new StringReader("100");
    Console.SetIn(_sr);
}

[TearDown]
public void TearDown()
{
    var standardOut = new StreamWriter(Console.OpenStandardOutput());
    standardOut.AutoFlush = true;
    Console.SetOut(standardOut);
    Console.SetIn(new StreamReader(Console.OpenStandardInput()));
 }

Then I would use '_sw.ToString()' within the tests to verify what was written to the stream.

Are there any major drawbacks of using setup or teardown methods for this? Would this similar to redirecting with a using statement? E.g.

using (StringWriter sw = new StringWriter())
{
    ...
}
Community
  • 1
  • 1
Daryn
  • 3,394
  • 5
  • 30
  • 41

1 Answers1

2

Are there any major drawbacks of using setup or teardown methods for this?

Yes, although it may not be measurable.

The way Setup and TearDown method is described here, two new disposable objects are created for every test, but they are never disposed of. They'll eventually go out of scope and be finalised when the garbage collector runs, but it may happen in a less deterministic fashion. In theory, it'll use more memory and processor instructions than if they were deterministically disposed of, but as Knuth taught us 40 years ago, we should measure instead of engaging in premature optimisations.

My main problem with using mutable state and Implicit Setup and Teardown is that it's not thread-safe, so if you ever want to run your unit tests in parallel, you can't.

Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
  • Thank you for the prompt answer. With regards to the first point about disposing objects, would it help to call `_sw.Dispose();` in the teadown? Will this dispose of the object in a more deterministic way? Is the `using` still preferred? – Daryn Mar 26 '15 at 07:45
  • With regards running the tests in parallel, would this still work as we are setting Console.SetOut. Is that not still shared mutable state in this context? – Daryn Mar 26 '15 at 07:53
  • It *may* help to call `_sw.Dispose()` and `_sr.Dispose()` in `TearDown`, but as I also wrote, it may be a premature micro-optimization... The only way to know is to measure... Whether or not `Console.SetOut` is thread-safe I don't know, but if it isn't, then you'd never be able to run these particular tests in parallel. – Mark Seemann Mar 26 '15 at 08:04