2017-02-21 10 views
1

Я реализовал структуру данных стека на основе массива вместе с соответствующими модульными тестами. Этот стек реализует мой интерфейс IStack. Таким образом, на данный момент, мой класс UT выглядит примерно так:Инъекция зависимостей в модульных тестах

[TestClass] 
public class Stack_ArrayBased_Tests 
{  
    //check against empty collection 
    [TestMethod] 
    public void IsEmpty_NoElements() 
    { 
     var myStack = new Stack_ArrayBased_Example1(10); 

     var exp = true; 
     var act = myStack.IsEmpty(); 
     Assert.AreEqual(exp, act); 
    } 

Теперь я собираюсь реализовать связанный список стек на основе. Этот стек будет наследовать от того же интерфейса IStack.

Я хотел был бы Unit Test связанного списка Stack. Поскольку оба наследуются от одного и того же интерфейса, я должен иметь возможность воспользоваться уже реализованным модульным тестом, чтобы предотвратить ненужное дублирование кода.

Что было бы лучшим способом создать два отдельных класса тестов модулей, один для Stack на основе массива, а другой для Stack String, связанный с Linked List, который будет использовать те же методы тестирования единицы измерения? Я предполагаю, что инъекция зависимостей будет ответом, но как я буду заниматься этим?

+0

Как и с любым другим кодом, вы должны Реорганизовать код, который принадлежит оба сценария в собственный класс, поэтому его можно использовать в разных случаях использования. Поэтому, когда вы уже * имеете * реализацию для тестового случая 1 рефакторируете поведение в свой класс и используете экземпляры в обоих тестах. – HimBromBeere

ответ

2

Вы можете отделить логику другим способом.

[TestMethod] 
public void IsEmpty_NoElements_ArrayBased() 
{ 
    var myStack = new Stack_ArrayBased_Example1(10); 
    IsEmpty_NoElements(myStack) 
} 

[TestMethod] 
public void IsEmpty_NoElements_LinkedListBased() 
{ 
    var myStack = new Stack_LinkedListBased_Example1(10); 
    IsEmpty_NoElements(myStack) 
} 

public void IsEmpty_NoElements(IStack myStack) 
{ 
    var exp = true; 
    var act = myStack.IsEmpty(); 
    Assert.AreEqual(exp, act); 
} 
4

Инъекционная инъекция никогда не является ответом на тесты.

Вы не испытываете абстракции, это невозможно, вы проверяете конкретные реализации. Однако вы можете вообразить абстракции, интерфейсы, абстрактные классы.

Вы можете создать некоторый класс с единственной целью повторного использования кода, и вы вызываете этот класс из своих методов тестирования, это нормально и полностью выполнимо.

Вам по-прежнему потребуется два тестовых класса по одному для каждой конкретной реализации, и вы оба вызываете этот новый класс, который вы создали. Это позволяет избежать дублирования кода.

0

Скажем, мы имеем следующую

public interface IStack 
{ 
    bool IsEmpty { get; } 
} 

public class StackImpl1 : IStack 
{ 
    public StackImpl1(int size) 
    { 
    IsEmpty = true; 
    } 

    public bool IsEmpty { get; } 
} 

public class StackImpl2 : IStack 
{ 

    public StackImpl2(int size) 
    { 
    IsEmpty = true; 
    } 

    public bool IsEmpty { get; } 
} 

И мы хотим реализовать тест IsEmpty_OnCreation() из ОП. We может сделать общий тест и добавить несколько invokers (по одному для каждой тестируемой реализации). Проблема заключается в масштабировании.

Для каждой новой части функциональности для тестирования нам нужно добавить

1) реализации теста
2) Invoker для каждой реализации, чтобы проверить.

Для каждой новой реализации, которую мы вводим, нам нужно добавить invoker для каждого существующего теста.

Можно использовать наследование, чтобы сделать большую часть работы для нас

public abstract class StackTest 
{ 
    protected abstract IStack Create(int size); 

    [TestMethod] 
    public void IsEmpty_NoElements() 
    { 
    var myStack = Create(10); 

    var exp = true; 
    var act = myStack.IsEmpty; 
    Assert.AreEqual(exp, act); 

    } 
} 

[TestClass] 
public class StackImp1Fixture : StackTest 
{ 
    protected override IStack Create(int size) 
    { 
    return new StackImpl1(size); 
    } 
} 

[TestClass] 
public class StackImp2Fixture : StackTest 
{ 
    protected override IStack Create(int size) 
    { 
    return new StackImpl2(size); 
    } 
} 

тесты генерируются в каждом производном арматуре.

Если мы хотим добавить новый тест, добавим его в класс StackTest и он будет автоматически включен в каждое производное оборудование.

Если мы добавим третью реализацию IStack, мы просто добавим новое тестовое оборудование, основанное на StackTest и переопределяющем метод создания.

Примечание:
Если классы Испытуемых имеют конструктор по умолчанию, то же форма может быть использована с Generic StackTest в качестве основы

public class GenStackTest<TStack> where TStack : IStack, new() 
{ 

    [TestMethod] 
    public void IsEmpty_NoElements() 
    { 
    var myStack = new TStack(); 

    var exp = true; 
    var act = myStack.IsEmpty; 
    Assert.AreEqual(exp, act); 

    } 
} 

[TestClass] 
public class GenStack1Fixture : GenStackTest<StackImpl1> 
{ 
} 

[TestClass] 
public class GenStack2Fixture : GenStackTest<StackImpl2> 
{ 
} 
Смежные вопросы