NUniteLite 3.11.0 throwing Null Reference Exception with AutoRun in LINQpad
Asked Answered
K

3

1

The following LINQPad query throws NullReferenceException in the try-catch block:

void Main()
{
    var specialFolder = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
    var workingFolder = $@"{specialFolder}\NUnitLiteTestResults";
    var args = new[]
        {
            "--labels=All",
            "--nocolor",
            "--noheader",
            $"--work={workingFolder}"
        };

    try
    {
        (new AutoRun()).Execute(args);
    }
    catch (NullReferenceException ex)
    {
        ex.Dump("why?");
    }
}

public class Runner
{
    /*
        public static int Main(string[] args) {
            return new AutoRun(Assembly.GetCallingAssembly()).Execute(new String[] {"--labels=All"});
        }
    */
    [TestFixture]
    public class FooTest
    {
        [Test]
        public void ShouldCheckBoolean()
        {
            Assert.IsTrue(true);
        }

        [Test]
        public void ShouldCompareNumbers()
        {
            Assert.AreEqual(2, 2);
        }

        [Test]
        public void ShouldCompareStrings()
        {
            Assert.AreEqual("abc", "abc");
        }

        [Test]
        public void TestCompareLists()
        {
            Assert.AreEqual(new int[] { 1, 2, 3 }, new int[] { 1, 2, 3 });
        }
    }
}

Am I missing any setup code here?

Exception (there is no C:\src\nunit folder on my machine):

Object reference not set to an instance of an object.
 at System.IO.TextWriter.Dispose()
   at System.IO.TextWriter.Dispose()
   at System.IO.TextWriter.SyncTextWriter.Dispose(Boolean disposing)
   at System.IO.TextWriter.Dispose()
   at NUnit.Common.ExtendedTextWrapper.Dispose(Boolean disposing) in C:\src\nunit\nunit\src\NUnitFramework\nunitlite\ExtendedTextWrapper.cs:line 83
   at System.IO.TextWriter.Dispose()
   at NUnitLite.TextRunner.Execute(String[] args) in C:\src\nunit\nunit\src\NUnitFramework\nunitlite\TextRunner.cs:line 149
   at NUnitLite.AutoRun.Execute(String[] args) in C:\src\nunit\nunit\src\NUnitFramework\nunitlite\AutoRun.cs:line 82
   at UserQuery.Main()
Karolynkaron answered 18/10, 2018 at 22:55 Comment(3)
Can you add the exception stack trace?Ahrendt
Have you added (through Linqpad) references to both the NUnit Framework and NUnitLite?Discretion
I have only added the NUnitLite NuGet package via LINQPad.Karolynkaron
C
3

The problem is that the runner attempts to dispose the output and error streams that linqpad is using. Ultimately, since it's currently in use and meant to be left open, it leads to the error.

You can avoid this issue if you redirect the output and error streams to a file either on the console itself or arguments to the runner (--out and --err params).

Though, the whole point of running it in linqpad is so that the results appear in the results pane. So what you could do is create a wrapper around the streams that ignores the dispose calls.

void Main()
{
    var workDir = Path.Combine(Util.MyQueriesFolder, "nunit-work");
    var args = new string[]
    {
        "-noh",
        $"--work={workDir}",
    };
    RunUnitTests(args);
}

void RunUnitTests(string[] args, Assembly assembly = null)
{
    Console.SetOut(new NoDisposeTextWriter(Console.Out));
    Console.SetError(new NoDisposeTextWriter(Console.Error));
    new AutoRun(assembly ?? Assembly.GetExecutingAssembly()).Execute(args);
}

class NoDisposeTextWriter : TextWriter
{
    private readonly TextWriter writer;
    public NoDisposeTextWriter(TextWriter writer) => this.writer = writer;

    public override Encoding Encoding => writer.Encoding;
    public override IFormatProvider FormatProvider => writer.FormatProvider;
    public override void Write(char value) => writer.Write(value);
    public override void Flush() => writer.Flush();
    // forward all other overrides as necessary

    protected override void Dispose(bool disposing)
    {
        // no nothing
    }
}
Coates answered 13/12, 2018 at 0:1 Comment(0)
A
1

Per Jeff's answer above place NoDisposeTextWriter as a public class in your MyExtensions so it's always available.

Then your main can look like the following:

void Main()
{
    var cwd = Util.MyQueriesFolder;
    var args = new[] {
        "-noheader", 
        $"-work:{cwd}"
    };

    Console.SetOut(new NoDisposeTextWriter(Console.Out));
    Console.SetError(new NoDisposeTextWriter(Console.Error));
    new AutoRun(Assembly.GetExecutingAssembly()).Execute(args);
}

public class Foo{...}

[TextFixture]
public class TestFoo{...}
Aerospace answered 16/4, 2019 at 8:7 Comment(0)
W
0

If you want to reduce LOC from Jeff's answer, you can install FakeItEasy and write:

void Main()
{
    Console.SetOut(A.Fake<TextWriter>(o => o.Wrapping(Console.Out).ConfigureFake(f => A.CallTo(f).Where(m => m.Method.Name == "Dispose").DoesNothing())));
    Console.SetError(A.Fake<TextWriter>(o => o.Wrapping(Console.Error).ConfigureFake(f => A.CallTo(f).Where(m => m.Method.Name == "Dispose").DoesNothing())));
    new AutoRun().Execute(new string[]  {"-noh", $"--work={Path.Combine(Util.MyQueriesFolder, "nunit-work")}" }); //https://mcmap.net/q/355142/-nunitelite-3-11-0-throwing-null-reference-exception-with-autorun-in-linqpad
}
 
[Test]
public void SomeTest()
{
    Assert.Pass();
}
Weatherglass answered 16/9, 2021 at 9:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.