Dependency Injection in Unit Tests

11,484

Solution 1

You can separate logic in another method.

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

Solution 2

Dependency injection is never the answer when it comes to tests.

You are not testing abstractions, that's impossible, you test concrete implementations. You can however mock abstractions, interfaces, abstract classes.

You can create some class with the sole purpose of reusing code and you call that class from your test methods, that's ok and totally doable.

You will still need two test classes, one for each of your concrete implementations, and have both call this new class you created. This avoids code duplication.

Solution 3

Say we have the following

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

And we wish to implement the IsEmpty_OnCreation() test from the OP. We can make a common test and add multiple invokers (one for each implementation to be tested). The problem is scaling.

For each new piece of functionality to be tested we need to add

1) the test implementation
2) an invoker for each implementation to be tested.

For each new implementation we introduce, we need to add an invoker for each existing test.

It is possible to use inheritance to do most of the work for us

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

The tests are generated in each derived fixture.

If we want to add a new test, we add it to the StackTest class and it is automatically included in each derived fixture.

If we add a third implementation of IStack , we simply add a new test fixture deriving from StackTest and overriding the create method.

Note:
If the classes under test have default constructors, the same shape can be used with a Generic StackTest as the base

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>
{
}
Share:
11,484
lucas
Author by

lucas

I am a Senior Software Engineer. Most of my work is done in .NET environment writing web and windows application, windows and web services. I like studying and applying IT related concepts, and my main passion is programming and development. I love developing composite solutions combining various technologies. I consider myself a full stack developer, meaning, I develop complete solutions from the database design and implementation till the final product delivery.

Updated on June 15, 2022

Comments

  • lucas
    lucas almost 2 years

    I have implemented array based Stack Data Structure along with corresponding Unit Tests. This Stack implements my IStack interface. So at the moment, my UT class looks something like that:

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

    Now, I am about to implement Linked List based Stack. This Stack will inherit from the same IStack interface.

    I would like to Unit Test the linked list Stack as well. Since both are inheriting from the same interface, I should be able to take advantage of already implemented Unit Test, in order to prevent from unnecessary code duplication.

    What would be the best way to create two separate Unit Test classes, one for Array based Stack, and another for Linked List based Stack, that would use the same Unit Test methods? I assume Dependency Injection would be an answer, but how I would go about it?