所以基本上我有一个域对象和一个可以用该对象进行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();
}
}
这应该让我开始并给我一个失败的测试,因为throw将打破它(我也尝试实际实现方法没有运气)。但是测试人员(尝试了nunits GUI和resharpers测试跑步者)只是忽略了我的基础测试!它显示了所有 - 但报告为忽略。
所以我做了一点挖掘... NUnit在TextFixtureAttribute上有这个属性,它允许你指定你正在测试什么样的类型,所以我尝试了把属性
[TestFixture(typeof(Foo))]
首先是Base,还有Foo版本。当放在Foo版本时,它仍然只是忽略了从基础的测试,当我把它放在基础上...好吧它变成红色因为方法抛出异常,这将是好的,除非即使我做实际的实现在FooTests中,它们仍然无法工作(显然,基于TestFixture属性的基础测试永远不会知道哪些类从它继承,所以它如何知道找到实现)。
那我该坚持做什么?我可以在基础测试类中进行虚拟测试,然后在FooBaseRepositoryTests中覆盖它,只是从base调用实现,这是一个蹩脚的解决方案,我认为......
还有什么可做的?我错过了什么吗?请帮忙,有人...... :)
答案 0 :(得分: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>();
}
}
派生类将正确运行其所有父测试。关于这一点的唯一稍微混乱的部分是基类创建了一堆“忽略”测试,这不是很干净。
答案 1 :(得分:1)
当您在fixture类上使用属性[TestFixture(typeof(Foo))]
以便将其用于不同类型时;它不应该是抽象的。
如果在Foo fixture上使用,该类应该是通用的,而不是为Foo键入。
来自文档:
[TestFixture]
public class AbstractFixtureBase
{
...
}
[TestFixture(typeof(string))]
public class DerivedFixture<T> : AbstractFixtureBase
{
...
}
答案 2 :(得分:0)
我还没有尝试过你的例子,但你可以尝试将属性TestFixture和Test放在同一个类中。也尝试将它放入基类。