2

I need to run a test N times where the number N is supplied through an external file. So N is not compile time constant. How can I achieve this? I have tried implementing ITestAction and IFrameworkDriver like the following. When run a test in debug mode, the BeforeTest method is executed before the test runs and AfterTest after test is executed. I assumed Run method would be executed just to run the test, but it doesn't. Your help is appreciated.

[Extension]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class CustomRunner : Attribute, ITestAction, IFrameworkDriver
{

    private NUnit3FrameworkDriver frameworkDriver = new NUnit3FrameworkDriver(AppDomain.CurrentDomain);


    #region ITestAction
    public ActionTargets Targets => ActionTargets.Test;

    public bool IsTestRunning => throw new NotImplementedException();

    public void AfterTest(ITest test)
    {
        Console.WriteLine("After test is executed");
    }

    public void BeforeTest(ITest test)
    {
        Console.WriteLine("Before test is executed");
    }

    #endregion


    public string Load(string testAssemblyPath, IDictionary<string, object> settings)
    {
        Console.WriteLine("Testting");
        return frameworkDriver.Load(testAssemblyPath, settings);
    }

    public int CountTestCases(string filter)
    {
        Console.WriteLine("Testting");
        return frameworkDriver.CountTestCases(filter);
    }

    public string Run(ITestEventListener listener, string filter)
    {
        Console.WriteLine("Testting");
        return frameworkDriver.Run(listener, filter);
    }

    public string Explore(string filter)
    {
        Console.WriteLine("Testting");
        return frameworkDriver.Explore(filter);
    }

    public void StopRun(bool force)
    {
        Console.WriteLine("Testting");
        frameworkDriver.StopRun(force);
    }

    public string ID { get { return frameworkDriver.ID; } set { frameworkDriver.ID = value; } }
}

Test.cs

[TestFixture]
public class Test 
{
    [CustomRunner]
    [Test]
    public void JustATest()
    {
        Assert.True("a".Equals("a"));
    }
}

1 Answers1

1

NUnit 3 is based on a layered architecture: runners-engine-framework. As in any such architecture, the layers only communicate with one another through defined APIs and their classes are never mixed.

Engine extensions are part of the engine layer, which is capable of loading and running tests using any framework for which a driver exists. Specifically, a framework driver extension is written to connect the engine to a framework that it doesn't understand natively. Drivers are extensions to the engine and are not part of the framework they support. So your use of the IFrameworkDriver interface is wrong both in it's purpose (you don't have a new framework to connect and there's already an NUnit 3 framework driver) and in it's implementation (having an attribute reference the engine and provide a driver has no effect, since nothing will ever call it).

The ITestAction interface is a part of the framework and your action will, if used correctly, be called before and after each test is run. However, it has no impact on how the test is run.

Since you want an attribute that works like the existing RetryAttribute but takes it's count from a file, we might consider deriving the new class from RetryAttribute. Unfortunately, although not sealed, the class uses private members and has no virtual methods to override. It was not designed to be used as a base class.

OTOH, RetryAttribute is a very small class. My ultimate suggestion is that you simply copy and modify it. Looking closely at its implementation will clarify a lot of things about how custom attributes work for you.

Charlie
  • 12,928
  • 1
  • 27
  • 31