C# 单元测试中的依赖注入
我已经实现了基于数组的堆栈数据结构以及相应的单元测试。这个堆栈实现了我的IStack接口。所以现在,我的UT课程看起来是这样的:C# 单元测试中的依赖注入,c#,unit-testing,dependency-injection,C#,Unit Testing,Dependency Injection,我已经实现了基于数组的堆栈数据结构以及相应的单元测试。这个堆栈实现了我的IStack接口。所以现在,我的UT课程看起来是这样的: [TestClass] public class Stack_ArrayBased_Tests { //check against empty collection [TestMethod] public void IsEmpty_NoElements() { var myStack = new Stack_
[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接口继承
我还想对链表堆栈进行单元测试。由于两者都是从同一接口继承的,我应该能够利用已经实现的单元测试,以防止不必要的代码重复
创建两个单独的单元测试类(一个用于基于数组的堆栈,另一个用于基于链表的堆栈)的最佳方法是什么,它们将使用相同的单元测试方法?我假设依赖注入是一个答案,但我会怎么做呢?您可以用另一种方法分离逻辑
[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);
}
当涉及到测试时,依赖注入永远不是答案 你不是在测试抽象,这是不可能的,你是在测试具体的实现。但是,您可以模拟抽象、接口和抽象类 您可以创建一些类,其唯一目的是重用代码,然后从测试方法中调用该类,这是完全可行的
您仍然需要两个测试类,每个测试类一个用于您的具体实现,并让它们都调用您创建的这个新类。这样可以避免代码重复。假设我们有以下几点
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\u 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
类中,它将自动包含在每个派生的fixture中
如果我们添加IStack
的第三个实现,我们只需添加一个从StackTest
派生并覆盖create方法的新测试夹具
注:如果被测试的类具有默认构造函数,那么可以将相同的形状与通用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>
{
}
公共类测试,其中TStack:IStack,new()
{
[测试方法]
公共无效是空的元素()
{
var myStack=new TStack();
var exp=真;
var act=myStack.IsEmpty;
主张平等(exp,act);
}
}
[测试类]
公共类Genstack1混合:GenStackTest
{
}
[测试类]
公共类Genstack2混合:GenStackTest
{
}
与任何其他代码一样,您应该将属于这两种场景的代码重构为自己的类,以便在不同的用例中使用。因此,当您已经有了测试用例1的实现时,将行为重构到它自己的类中,并在两个测试中使用实例。