-3
public static class Utils
{
    /// <summary>
    /// Creates a Writer object that writes either to a file or to a console stream.
    /// </summary>
    /// <param name="outFname">file name, "stdout" or "stderr"</param>
    /// <param name="ifAppend">if true, append to existing file; otherwise, overwrite</param>
    /// <returns>A TextWriter object that can be used to write output.</returns>
    public static StreamWriter OutWriter(string outFname, bool ifAppend)
    {
        if (string.IsNullOrEmpty(outFname) || outFname == "stdout")
        {
            return new StreamWriter(Console.OpenStandardOutput());
        }
        else if (outFname == "stderr")
        {
            return new StreamWriter(Console.OpenStandardError());
        }
        else
        {
            FileStream fileStream;
            if (ifAppend)
                fileStream = new FileStream(outFname, FileMode.Append, FileAccess.Write, FileShare.None);
            else
                fileStream = new FileStream(outFname, FileMode.Create, FileAccess.Write, FileShare.None);
            return new StreamWriter(fileStream, Encoding.UTF8);
        }
    }
}
[TestMethod]
public void OutWriter_ShouldReturnConsoleError_ForStderr()
{
    // Capture the current Console.Error
    TextWriter originalError = Console.Error;

    // Redirect Console.Error to a StringWriter to capture the output
    StringWriter errorWriter = new StringWriter();
    Console.SetError(errorWriter);

    using (StreamWriter writer = Utils.OutWriter("stderr", false))
    {
        // Write something to the StreamWriter
        writer.WriteLine("Test error output");
        writer.Flush(); // Ensure the output is flushed
    }

    // Reset the Console.Error to its original state
    Console.SetError(originalError);

    // Verify that the output was written to the StringWriter
    string expectedOutput = "Test error output" + Environment.NewLine;
    string actualOutput = errorWriter.ToString();
    Assert.AreEqual(expectedOutput, actualOutput, "The writer should write to Console.Error.");
}

Test output:

Test Name:  OutWriter_ShouldReturnConsoleError_ForStderr
Test FullName:  PdbLibTests.UtilsTests.OutWriter_ShouldReturnConsoleError_ForStderr
Test Source:    C:\git\MyProject_csharp\unit_test_for_Utils\UtilsTests.cs : line 15
Test Outcome:   Failed
Test Duration:  0:00:00.1644456

Result StackTrace:  at PdbLibTests.UtilsTests.OutWriter_ShouldReturnConsoleError_ForStderr() in C:\git\MyProject_csharp\unit_test_for_Utils\UtilsTests.cs:line 37
Result Message: 
Assert.AreEqual failed. Expected:<Test error output
>. Actual:<>. The writer should write to Console.Error.

Why isn't the unit-test succeeding?

How can I make it succeed?


Then I tried mocking the console:

public static class MockConsole
{
    public static StringWriter ErrorWriter { get; private set; }
    public static TextWriter OriginalError { get; private set; }

    public static void Initialize()
    {
        OriginalError = Console.Error;
        ErrorWriter = new StringWriter();
        Console.SetError(ErrorWriter);
    }

    public static void Reset()
    {
        Console.SetError(OriginalError);
        ErrorWriter.Dispose();
    }
}


[TestMethod]
public void OutWriter_ShouldReturnConsoleError_ForStderr()
{
    // Initialize mock console
    MockConsole.Initialize();

    using (StreamWriter writer = Utils.OutWriter("stderr", false))
    {
        // Write something to the StreamWriter
        writer.WriteLine("Test error output");
        writer.Flush(); // Ensure the output is flushed
    }

    // Capture the output written to the error writer
    string actualOutput = MockConsole.ErrorWriter.ToString();

    // Reset the console to its original state
    MockConsole.Reset();

    // Verify that the output was written to the StringWriter
    string expectedOutput = "Test error output" + Environment.NewLine;
    Assert.AreEqual(expectedOutput, actualOutput, "The writer should write to Console.Error.");
}

This also hasn't succeeded.

5
  • Why are you making a unit test that involves the console? Mock the console instead.
    – gunr2171
    Commented Oct 29 at 15:13
  • @gunr2171, Check the edit.
    – user366312
    Commented Oct 29 at 15:21
  • What's the point of OutWriter to begin with? The correct way to test this would be to use a stream as input. Once you do that though, OutWriter isn't very useful. If you want to log to the console or a file, it's a lot better (and faster, easier) to use a logging library like Serilog Commented Oct 29 at 15:30
  • BTW the StreamWriter use UTF8 without a BOM by default. You could simplify this code a lot by storing the generated stream in a variable and at the end use return new StreamWriter(stream);. Using switch expressions you could turn all this in 3-4 lines that pick a stream. I'd still use Serilog instead Commented Oct 29 at 15:33
  • 1
    As an aside, that's not how you should test Strings for equality...
    – Jon Skeet
    Commented Oct 29 at 16:07

1 Answer 1

1

I just checked the implementation: Console.OpenStandardError() opens a (new) standard error stream, regardless of what it was before. Use the Console.Error property to get the mock object you have assigned using Console.SetError().

Not the answer you're looking for? Browse other questions tagged or ask your own question.