单元测试中的依赖注入

时间:2017-02-21 12:58:39

标签: c# unit-testing dependency-injection

我已经实现了基于数组的堆栈数据结构以及相应的单元测试。这个Stack实现了我的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);
    }

现在,我即将实现基于链接列表的Stack。此Stack将继承自相同的IStack接口。

我想单独测试链表Stack。由于两者都是从相同的接口继承,我应该能够利用已经实现的单元测试,以防止不必要的代码重复。

创建两个单独的Unit Test类的最佳方法是什么,一个用于基于Array的Stack,另一个用于基于Linked List的Stack,它们将使用相同的Unit Test方法?我假设依赖注入将是一个答案,但我将如何去做呢?

3 个答案:

答案 0 :(得分:5)

在测试方面,依赖注入永远不是解决方案。

你没有测试抽象,这是不可能的,你测试具体的实现。但是,您可以模拟抽象,接口和抽象类。

您可以创建一些类,其唯一目的是重用代码,然后从测试方法中调用该类,这样就可以了,并且完全可行。

对于每个具体实现,您仍然需要两个测试类,并且都要调用您创建的这个新类。这可以避免代码重复。

答案 1 :(得分:1)

您可以在另一种方法中分离逻辑。

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

答案 2 :(得分:1)

说我们有以下

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

我们希望从OP实施IsEmpty_OnCreation()测试。我们可以进行常见测试并添加多个调用者(每个实现要测试一个)。问题在于扩展。

对于要测试的每个新功能,我们需要添加

1)测试实施
2)每个要测试的实现的调用者。

对于我们介绍的每个新实现,我们需要为每个现有测试添加一个调用程序。

可以使用继承为我们完成大部分工作

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派生的新测试夹具并覆盖create方法。

注意:
如果被测试的类具有默认构造函数,则可以使用相同的形状,并使用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>
{
}