Test-Driven Test Development

Making it Go Green

Running Tests in DLLs

What now? Well, remember our goal? “do whatever we need to do to make the test pass”

Let’s be naive and simply run every static method we find with Test in the name.

Update MiniSpec/Program.cs to the following:

using System;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;

foreach (var dll in args) {
    var dllPath = System.IO.Path.GetFullPath(dll);
    var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(dllPath);
    foreach (var type in assembly.GetTypes()) {
        var testMethods = type.GetMethods(BindingFlags.NonPublic | BindingFlags.Static)
            .Where(m => m.Name.Contains("Test"));
        foreach (var method in testMethods) {
            try {
                method.Invoke(null, null);
                Console.WriteLine($"PASS {method.Name}");
            } catch (Exception e) {
                Console.WriteLine($"FAIL {method.Name}");
                Console.WriteLine($"ERROR {e.Message}");
            }
        }
    }
}

Run the tests again with dotnet test (excerpt below)

Not found: PASS TestShouldPass
In value:  PASS <<Main>$>g__TestShouldPass|0_0
FAIL <<Main>$>g__TestShouldFail|0_1
ERROR Exception has been thrown by the target of an invocation.

Yikes, we tried but a few things are incorrect which we need to fix.

  • Name of the test is showing up as <<Main>$>g__TestShouldPass|0_0
  • ^— this should be: TestShouldPass
  • Exception message only says Exception has been thrown by the target of an invocation
  • ^— this should be Kaboom!

Fix Program.cs

Update MiniSpec/Program.cs to the following:

using System;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using System.Text.RegularExpressions;

foreach (var dll in args) {
    var dllPath = System.IO.Path.GetFullPath(dll);
    var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(dllPath);
    foreach (var type in assembly.GetTypes()) {
        var testMethods = type.GetMethods(BindingFlags.NonPublic | BindingFlags.Static)
            .Where(m => m.Name.Contains("Test"));
        foreach (var method in testMethods) {
            var displayName = method.Name;
            if (Regex.IsMatch(displayName, @"[^\w]"))
                displayName =
                    Regex.Match(displayName, @"Test([\w]+)").Value;
            try {
                method.Invoke(null, null);
                Console.WriteLine($"PASS {displayName}");
            } catch (Exception e) {
                Console.WriteLine($"FAIL {displayName}");
                Console.WriteLine($"ERROR {e.InnerException.Message}");
            }
        }
    }
}

Run the tests again with dotnet test (excerpt below)

Passed!  - Failed:     0, Passed:     1, Skipped:     0, Total:     1

Phew! We did it! Green, passing tests! Goodness gracious! Hooray!

Try it yourself!

bin/Debug/*/minispec.exe bin/Debug/*/MyTests.dll
PASS TestShouldPass
FAIL TestShouldFail
ERROR Kaboom!

On Linux: ./bin/Debug/*/minispec bin/Debug/*/MyTests.dll