Mike Makarov
Mike Makarov

Reputation: 1356

nUnit extension in the same assembly as tests

History: nUnit 3. I have tests with complex inheritance. A certain object is created within SetUp or OneTimeSetUp. Those methods are virtual. When this object is not closed, the leak occur.

Problem: The object is destroyed in TearDown or OneTimeTearDown, but those are only called when SetUp or OneTimeSetUp succeed. So when exception occurs somewhere within TearDown or OneTimeTearDown, the leak occurs. As I mentioned, there are multiple inheritance levels, so exception and critical object creation may happen in different classes, on the different stack frames.

What I want to do: I want to have ITestEventListenerto react on failure before the initialization finished and clean up the critical object.

What I tried: in my test assembly I created the class:

namespace My.Whatever.Tests.Web.Util
{
    [Extension(EngineVersion = "3.4")]
    public class NunitEventListener : ITestEventListener
    {
        public void OnTestEvent(string report)
        {
            Debug.WriteLine(report);
        }
    }
}

Then I tried running tests through

None seem to load the extension.

Question: what am I doing wrong?

Sources of info: https://github.com/nunit/docs/wiki/Event-Listeners , https://github.com/nunit/docs/wiki/Writing-Engine-Extensions

Upvotes: 0

Views: 398

Answers (1)

Charlie
Charlie

Reputation: 13726

The info about how extensions are located is found at https://github.com/nunit/docs/wiki/Engine-Extensibility#locating-addins which is linked from the second of the two references you mention.

Extensions are not searched for in your test assembly. We provided that in V2 for NUnit Addins as an easy way to test extensions, but it's a bit more complicated to do that for engine extensions. IMO it would be a good feature if we could make that work, but it involves making all extensions capable of being loaded and unloaded as new test assemblies are run. That's a major internal change to our extension service.

In the directory containing the engine assembly, you may find one or more files of type .addins. Whether there is one and how many and what they contain will depend on how you installed the runner and engine. That file has entries pointing to the extensions installed for that particular copy of the engine. See the above reference page for details.

In two cases, the location of extensions is more or less automatic, due to the presence of wild-card entries in the .addins file:

  1. If you install the console runner using NuGet any extensions installed as nuget packages are found.

  2. If you install the console runner using Chocolatey, any extensions installed by chocolatey are found.

In all other cases, I'm afraid that you would have to edit the .addins file manually.

In the specific case of the adapter, there is no .addins file and therefore no extensions are ever loaded. In theory, you could create such a file by hand and cause your extension to load, at least if the engine is installed in a directory to which you have access. That would be the case if you are using the nuget package. I suggest you first play with having your extension recognized under the console runner before trying this as it would involve additional complications.

BTW, not all third-party runners use the engine. If they are not using the engine at all, of course, it's not possible to provide extensions.

Update: I only just noticed your statement that TearDown and OneTimeTearDown are only run when SetUp orOneTimeSetUp` succeed. That's not a true statement. Both kinds of teardown only run if the corresponding setup is run, whether it succeeds or not. Of course, your teardowns have to be written to allow for the fact that the corresponding setup may not have run to completion, which can be tricky.

Upvotes: 1

Related Questions