Working with inherited fixtures and generic type restrictions

Asked by Matthew Kubicki

I'm am trying to test a hierarchy of classes, the first few layers of which are abstract. For example:

abstract Animal
-->absract Mammal
------>concrete Human

my approach when testing this sort of hierarchy is to use a test fixture for each tier:
AnimalTests
--->MammalTests
--------->HumanTests

This way I can keep the structure of the tests the same as the real code, and I can share the base class tests when I create new concrete types, i.e. Elephant also inherits Mammal and so ElephantTests inherits MammalTests, all the mammal tests are now applied to both humans and elephants.

I use generics on the test classes to allow me to call the extended methods on my test subject easily, so:
AnimalTests(of AnimalType as Animal)
--->MammalTests(of AnimalType as Mammal)
--------->HumanTests

This way each tier can call the methods it knows about on the test object. The two classes testing an abstract class have setups that will create a mock of the type, so AnimalTests creates a mock of Animal and MammalTests create a mock of Mammal. This behaviour is overriden by each class so when running HumanTests every tier gets a real Human to test.

This is nice in theory. But ...
To make all of this work I need to have my TestFixture attributes provide the correct type for the abstract tiers. So:
<TestFixture(gettype(Animal))>
Class AnimalTests(of AnimalType as Animal)

But when I get to MammalTests adding the following:
<TestFixture(gettype(Mammal))>
Class MammalTests(of AnimalType as Mammal)
It breaks because of the way Nunit applies test fixtures, it will try and run the base (AnimalTests) fixture against the MammalTests class, which will fail as the Animal class does not pass the constraint As Mammal on the MammalTests class.

I understand why the TestFixtures are applied like this but what I would ideally like is a way to stop it applying the base classes attributes to the inherited classes. The workaround I have found is that I can create my classes without the testfixture attribute and then inherit from them to apply the testfixture:
AnimalTests(of AnimalType as Animal)
---><TestFixture()>
---->AnimalTests_Actual inherits AnimalTests(of Animal)

This works, but causes me a problem with a tool I use for running tests, TestDriven.Net (http://www.testdriven.net/), its a great tool for running tests from within visual studio, it allows me to right click on a method in the editor or a file in the solution explorer and run tests with the debugger, code coverage etc. One requirement of this is that each class is concrete and has the TestFixture attribute applied. Since I can't apply this attribute to the class with the actual tests in I then can't select the individual test within AnimalTest or MammalTest to run.

This is all very frustrating.

TL;DR:
Can we have some way of stopping the TestFixture attributes being inherrited so we can restrict the generic type args as we go further from the base class? Or is there something I have missed that will let me have the TestFixture on each of my classes with tests in,and allow me to test the various tiers in my hierarchy separately and together.

Question information

Language:
English Edit question
Status:
Answered
For:
NUnit V2 Edit question
Assignee:
No assignee Edit question
Last query:
Last reply:
Revision history for this message
Charlie Poole (charlie.poole) said :
#1

Hi,

What you missed is that you should normally not place
TestFixtureAttribute on multiple
classes in a test hierarchy. Also, you must make the test classes you
don't plan to
to instantiate abstract, otherwise NUnit treats them as *separate*
test fixtures in
addition to using them for inheritance.

Here's how I'd try to do it. Since I don't really underatand the VB
syntax, I'll rewrite it in C#.

abstract class AnimalTests<AnimalType> where AnimalType : Animal { ... }

abstract class MammalTests<AnimalType> : AnimalTests<AnimalType> where
AnimalType : Mammal { ... }

[TestFixture] // optional so long as the class contains tests
publc class HumanTests : AnimalTests<Human> { ... }

In other words, this really isn't a generic fixture at all!

Charlie

On Fri, Sep 20, 2013 at 7:31 AM, Matthew Kubicki
<email address hidden> wrote:
> New question #236049 on NUnit V2:
> https://answers.launchpad.net/nunitv2/+question/236049
>
> I'm am trying to test a hierarchy of classes, the first few layers of which are abstract. For example:
>
> abstract Animal
> -->absract Mammal
> ------>concrete Human
>
> my approach when testing this sort of hierarchy is to use a test fixture for each tier:
> AnimalTests
> --->MammalTests
> --------->HumanTests
>
> This way I can keep the structure of the tests the same as the real code, and I can share the base class tests when I create new concrete types, i.e. Elephant also inherits Mammal and so ElephantTests inherits MammalTests, all the mammal tests are now applied to both humans and elephants.
>
> I use generics on the test classes to allow me to call the extended methods on my test subject easily, so:
> AnimalTests(of AnimalType as Animal)
> --->MammalTests(of AnimalType as Mammal)
> --------->HumanTests
>
> This way each tier can call the methods it knows about on the test object. The two classes testing an abstract class have setups that will create a mock of the type, so AnimalTests creates a mock of Animal and MammalTests create a mock of Mammal. This behaviour is overriden by each class so when running HumanTests every tier gets a real Human to test.
>
> This is nice in theory. But ...
> To make all of this work I need to have my TestFixture attributes provide the correct type for the abstract tiers. So:
> <TestFixture(gettype(Animal))>
> Class AnimalTests(of AnimalType as Animal)
>
> But when I get to MammalTests adding the following:
> <TestFixture(gettype(Mammal))>
> Class MammalTests(of AnimalType as Mammal)
> It breaks because of the way Nunit applies test fixtures, it will try and run the base (AnimalTests) fixture against the MammalTests class, which will fail as the Animal class does not pass the constraint As Mammal on the MammalTests class.
>
> I understand why the TestFixtures are applied like this but what I would ideally like is a way to stop it applying the base classes attributes to the inherited classes. The workaround I have found is that I can create my classes without the testfixture attribute and then inherit from them to apply the testfixture:
> AnimalTests(of AnimalType as Animal)
> ---><TestFixture()>
> ---->AnimalTests_Actual inherits AnimalTests(of Animal)
>
> This works, but causes me a problem with a tool I use for running tests, TestDriven.Net (http://www.testdriven.net/), its a great tool for running tests from within visual studio, it allows me to right click on a method in the editor or a file in the solution explorer and run tests with the debugger, code coverage etc. One requirement of this is that each class is concrete and has the TestFixture attribute applied. Since I can't apply this attribute to the class with the actual tests in I then can't select the individual test within AnimalTest or MammalTest to run.
>
> This is all very frustrating.
>
> TL;DR:
> Can we have some way of stopping the TestFixture attributes being inherrited so we can restrict the generic type args as we go further from the base class? Or is there something I have missed that will let me have the TestFixture on each of my classes with tests in,and allow me to test the various tiers in my hierarchy separately and together.
>
>
>
> --
> You received this question notification because you are an answer
> contact for NUnit V2.

Can you help with this problem?

Provide an answer of your own, or ask Matthew Kubicki for more information if necessary.

To post a message you must log in.