Unit Testing Console Application in Visual Studio

I have a test project in Visual Studio that I would like to use to test my console application (in the same solution).

I am trying to configure the tests that invoke a console application with certain parameters, and compare the actual output with what I expect, and then skip / fail my usual Assert statements accordingly.

The best way to do this that I can come up with is to run the exe application using System.Diagnostics.Process inside the unit test. It works. I can read the result, and all is well.

The problem I am facing is when I want to set a breakpoint inside the console application code, so I can do some debugging. Because Process launches a console application, Visual Studio does not watch the console application, so it wonโ€™t break. There is nothing like "Wait for a request from an external application", as it is in web applications, and I understand why, but basically what I'm looking for.

So my question is: is there a way to configure these unit tests inside Visual Studio, where can I still debug the console application? The only workaround I can come up with is to set the โ€œStartโ€ action in the console application to run an external program that will call MSTest.exe, and run the appropriate unit tests this way. But this seems like a problem that I just think about it wrong, and in fact there is a much more obvious solution.

+3
source share
3 answers

Make the console application as thin as possible and move all of your business logic into domain classes. For instance.

class Program
{
    static void Main(string[] args)
    {
       Foo foo = new Foo(args);
    }
}

After that, you can easily write unit tests for your Foo class.

+10

Unit test . , - TextReader TextWriter. .

+1

, unit test #, NUnit Test - Looping - # , , , , , "" . .

, - , (, , , ), , Process.Start. .NET 4.5 xunit:

[Theory]
[MemberData("YourStaticDataProviderField")]
public async void SomeTest(string initialString, string resultString, params int[] indexes)
{
    using (var consoleInStream = new AnonymousPipeServerStream(PipeDirection.Out))
    using (var consoleOutStream = new AnonymousPipeServerStream(PipeDirection.In))
    using (var writer = new StreamWriter(consoleInStream, Encoding.Default, 1024, true))
    using (var reader = new StreamReader(consoleOutStream, Encoding.Default, false, 1024, true))
    using (var tokenSource = new CancellationTokenSource())
    {
        // AutoFlush must be set to true to emulate actual console behavior,
        // else calls to Console.In.Read*() may hang waiting for input.
        writer.AutoFlush = true;

        Task programTask = Task.Run(() =>
        {
            using (var consoleInReader =
                new StreamReader(new AnonymousPipeClientStream(PipeDirection.In,
                                                               consoleInStream.GetClientHandleAsString())))
            using (var consoleOutWriter =
                new StreamWriter(new AnonymousPipeClientStream(PipeDirection.Out,
                                                               consoleOutStream.GetClientHandleAsString())))
            {
                // Again, AutoFlush must be true
                consoleOutWriter.AutoFlush = true;
                Console.SetIn(consoleInReader);
                Console.SetOut(consoleOutWriter);
                // Of course, pass any arguments your console application
                // needs to run your test.  Assuming no arguments are
                // needed:
                Program.Main(new string[0]);
            }
        }, tokenSource.Token);

        // Read and write as your test dictates.
        await writer.WriteLineAsync(initialString.Length.ToString());
        await writer.WriteLineAsync(initialString);
        await writer.WriteLineAsync(indexes.Length.ToString());
        await writer.WriteLineAsync(String.Join(" ", indexes));

        var result = await reader.ReadLineAsync();

        await writer.WriteLineAsync();

        // It is probably a good idea to set a timeout in case
        // the method under test does not behave as expected (e.g.,
        // is still waiting for input).  Adjust 5000 milliseconds
        // to your liking.
        if (!programTask.Wait(5000, tokenSource.Token))
        {
            tokenSource.Cancel();
            Assert.False(true, "programTask did not complete");
        }

        // Assert whatever your test requires.
        Assert.Null(programTask.Exception);
        Assert.Equal(resultString, result);
    }
}

, , .NET 3.5 , -. AnonymousPipe(Server|Client)Stream .NET 3.5. unit test .

System.IO.Pipes.AnonymousPipeServerStream System.IO.Pipes.AnonymousPipeClientStream . , , , MemoryStream , , . Program.Main(string[]) , unit test . AnonymousPipeClientStream , .

programTask, (, xunit, - Assert.ThrowsAsync<ExpectedException>(Func<Task>) ).

+1
source

All Articles