Я думаю, что вы можете решить эту проблему, используя абстрактный базовый класс, который содержит некоторые тесты, с абстрактным методом, который получает конкретную реализацию.
Это все еще требует небольшого кода в каждом конкретном классе теста реализации, но должно гарантировать, что если вы измените реализацию вне базового класса, ваши конструкторы все еще будут тестироваться.
Я только что сделал нечто подобное, чтобы протестировать метод, который для многих реализаций является операцией без операции (он просто возвращает то, что ему было дано), но для некоторых реализаций он что-то делает, и поэтому тесты кода операции не выполняются. единый базовый класс с абстрактным методом для получения объекта для тестирования (получает экземпляр интерфейса, в котором живет метод no op), и конкретные реализации, которые должны быть просто no op, расширяют этот класс и переопределяют абстрактный метод для возврата экземпляр класса, на котором мы хотим протестировать методы.
это помогло мне решить мою проблему, надеюсь, это поможет и вам.
public abstract class BaseClass
{
public abstract void CallConstructor(SomeType arg1, SomeType2 arg2);
[Test]
public void Constructor_WhenArg1IsNull_ArgumentNullExceptionIsThrown()
{
Assert.Throws<ArgumentNullException>(()=>CallConstructor(null, new SomeType2()));
}
[Test]
public void Constructor_WhenArg2IsNull_ArgumentNullExceptionIsThrown()
{
Assert.Throws<ArgumentNullException>(()=>CallConstructor(new SomeType(), null));
}
}
[TestFixture]
public class ConcreteImplementation1Tests : BaseClass
{
public override void CallConstructor(SomeType arg1, SomeType2 arg2)
{
new ConcreteImplementation1(arg1,arg2);
}
}
[TestFixture]
public class ConcreteImplementation2Tests : BaseClass
{
public override void CallConstructor(SomeType arg1, SomeType2 arg2)
{
new ConcreteImplementation2(arg1,arg2);
}
}
в дополнение к этому та же самая техника может использоваться для тестирования общего
функциональность для всех классов, которые реализуют интерфейс. Используя IList в качестве примера:
public abstract class ListImplementationsCommonTests
{
public abstract IList GetListImplementation();
[Test]
public void Add_WhenValidItemIsAdded_ItCanBeFound()
{
IList list = GetListImplementation();
object item = new Object();
list.Add(item);
Assert.That(list.Contains(item));
}
[Test]
public void Add_WhenNullIsAdded_ArgumentNullExceptionIsThrown()
{
IList list = GetListImplementation();
Assert.Throws<ArgumentNullException>(()=>list.Add(null));
}
...
//more common tests
...
}
Затем каждая реализация IList (например, ArrayList, LinkedList, DoubleLinkedList, SortedList и т. Д.) Может быть затем протестирована с одним и тем же кодом без необходимости повторять одни и те же тесты снова и снова:
[TestFixture]
public class ArrayListTests: ListImplementationCommonTests
{
public override IList GetListImplementation()
{
return new ArrayList();
}
...
//Extra specific tests for the ArrayList
}
[TestFixture]
public class LinkedListTests: ListImplementationCommonTests
{
public override IList GetListImplementation()
{
return new LinkedList();
}
...
//Extra specific tests for the LinkedList
}
[TestFixture]
public class SortedListTests: ListImplementationCommonTests
{
public override IList GetListImplementation()
{
return new SortedList();
}
...
//Extra specific tests for the SortedList
}