Как я могу создать общий BaseTest с NUnit, который я могу наследовать и иметь тесты из базового прогона?

Итак, в основном у меня есть объект домена и общий репозиторий, который может выполнять операции CRUD с этим объектом.

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

Итак, у меня есть несколько реализаций этого интерфейса, по одному для каждого объекта домена.

Я хотел бы написать некоторые интеграционные тесты (используя nunit), и для этого я решил, что сделаю BaseRepositoryTest - вот так:

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);
    }
}

Теперь для каждого объекта домена я должен был бы реализовать, как инициализировать репозиторий и как создать тестовый объект, который кажется справедливым, учитывая, что они будут разными...

Все, что мне нужно сделать, это правильно записать фактическое тестовое крепление? Вот так:

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

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

Это должно заставить меня начать и дать мне неудачный тест, так как бросок сломает его (я также попытался фактически реализовать методы без везения). Но тестировщики (попробовали оба nunits GUI и resharpers test runner) просто игнорировали мой базовый тест! Он отображается и все - но сообщается как игнорируется.

Итак, я немного поработал... NUnit имеет это свойство в TextFixtureAttribute, которое позволяет вам указать, какие вы тестируете, поэтому я попытался поместить атрибут

[TestFixture(typeof(Foo))]

Сначала база, а также версия Foo. Когда он помещается в версию Foo, он все еще просто игнорирует тест из базы, и когда я кладу его на базу... ну, он становится красным, потому что методы генерируют исключения, что было бы хорошо, за исключением того, что даже когда я выполняю фактическую реализацию в FooTests они все равно не сработают (очевидно, базовый тест, учитывая атрибут TestFixture, никогда не узнает, какие классы наследуют его, так как он узнает, чтобы найти реализацию).

Так что же мне делать? Я могу сделать тест в базовом тестовом классе виртуальным, а затем переопределить его в FooBaseRepositoryTests, только чтобы вызвать реализацию из базы, которая является хромым решением, которое я думаю...

Что еще нужно делать? Я что-то упускаю? Пожалуйста, помогите, кто-то...:)

Ответ 1

Когда вы используете атрибут [TestFixture(typeof(Foo))] в классе прибора, чтобы использовать его для разных типов; он не должен быть абстрактным.

Если используется в Foo fixture, этот класс должен быть общим и не набираться для Foo.

Из документов:

[TestFixture]
public class AbstractFixtureBase
{
    ...
}

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

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

Ответ 2

У меня недавно была проблема, и я нашел другое решение. У меня есть общий интерфейс IRepository, который я хочу тестировать с несколькими реализациями, поэтому я создал базовый класс, который игнорирует себя во время установки, но это поведение переопределяется его потомками:

[TestFixture]
public class AbstractRepositoryTests
{
    protected IRepository _repository;

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

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

Затем я переопределяю поведение установки в моем потомке, чтобы создать экземпляр объекта репозитория, а не игнорировать все тесты:

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

Производный класс будет корректно выполнять все свои родительские тесты. Единственная немного грязная часть об этом заключается в том, что базовый класс создает кучу тестов "Ignored", что не очень чисто.

Ответ 3

Я не пробовал ваш пример, но вы можете попробовать, если вы поместите атрибуты TestFixture и Test в один класс. Попробуйте также поместить его в базовый класс.