开发者

How can I create a generic BaseTest with NUnit that I can inherit from and have tests from the base run?

开发者 https://www.devze.com 2023-01-13 17:58 出处:网络
So basically i have a domain object and a generic repository that can do CRUD operations with that object.

So basically i have a domain object and a generic repository that can do CRUD operations with that object.

public interface IBaseRepository<T> where T : BaseEntity
{
    void Add(T entity);
    void Remove(T entity);
    T ById(int id);
    IEnumerable<T> All();
}

So I have several implementations of this interface, one for each domain object.

I would like to write some integration tests (using nunit) and for that i figured i'd make a BaseRepositoryTest - like this:

public abstract class BaseRepositoryTests<T> where T : BaseEntity
{
    public abstract IBaseRepository<T> GetRepository();
    public abstract T GetTestEntity();

    [Test]
    public void AddWhenCallingAddsObjectToDatabase()
    {
        IBaseRepository<T> repository = GetRepository();
        T entity = GetTestEntity();

        repository.Add(entity);
    }
}

Now, for each domain object i would have to implement how to initialize the R开发者_JAVA技巧epository and how to create a test entity, which seems fair, given they would be different...

All i have to do now is writing the actual test fixture right? Like this:

[TestFixture]
public class FooRepositoryTests: BaseRepositoryTests<Foo>
{
    public override IBaseRepository<Foo> GetRepository()
    {
        throw new NotImplementedException();
    }

    public override Foo GetTestEntity()
    {
        throw new NotImplementedException();
    }
}

This should get me started and give me a failed test since the throw will break it (i also tried actually implementing the methods with no luck). But the testrunners (tried both nunits GUI and resharpers test runner) just ignore my base test! It shows up and all - but reported back as Ignored.

So i did a little bit of digging... NUnit have this property on the TextFixtureAttribute that lets you specify what kind of you are testing so i tried putting the attribute

[TestFixture(typeof(Foo))]

On first the Base and also the Foo version. When put on the Foo version it still just ignores the test from the base, and when i put it on the base... well it turns red because the methods throws exceptions, which would be good except that even when i do the actual implementation in FooTests, they still won't work (obviously the Base test given the TestFixture attribute would never know what classes inherit from it, so how would it know to find the implementation).

So what am I stuck to do? I could make the test in the base test class virtual and then override it in FooBaseRepositoryTests, only to call the implementation from base, which is a lame solution i think...

What else is there to do? Am I missing something? Please help, someone... :)


I had this issue recently and found a different workaround. I have a generic IRepository interface that I want to be able to test with multiple implementations, so I created a base class that ignores itself during setup, but this behavior is overridden by its descendants:

[TestFixture]
public class AbstractRepositoryTests
{
    protected IRepository _repository;

    [SetUp]
    public virtual void SetUp()
    {
        Assert.Ignore();
    }

    [Test]
    public void AddToRepository()
    {
        // Place logic using _repository here
    }
}

I then override the setup behavior in my descendant to instantiate a repository object rather than ignoring all tests:

public class InMemoryRepositoryTests : AbstractRepositoryTests
{
    [SetUp]
    public override void SetUp()
    {
        _repository = new InMemoryRepository<string>();
    }
}

The derived class will run all of its parent tests properly. The only slightly messy part about this is that the base class creates a bunch of "Ignored" tests, which isn't very clean.


When you're using the attribute [TestFixture(typeof(Foo))] on the fixture class in order to use it for different types; it's not supposed to be abstract.

If used on the Foo fixture, that class should be generic, and not typed for Foo.

From the docs:

[TestFixture]
public class AbstractFixtureBase
{
    ...
}

[TestFixture(typeof(string))]
public class DerivedFixture<T> : AbstractFixtureBase
{
    ...
}

http://www.nunit.org/index.php?p=testFixture&r=2.5.5


I have not tried out your example but you could try if you put the attributes TestFixture and Test in the same class. Try also to put it into the base class.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号