1

I understand using DI for dependencies and mocking them for unit tests. However when I have multiple implementations for the current feature which I am unit testing how do I inject them into the unit test.

Ex: QuickSort or MergeSort

public class TestSort
{
  ISort sort = null;
    [TestInitialize]
    public void Setup()
    {
        sort = new MergeSort(); // or any implementation which need to be injected on setup
    }
Pacchy
  • 73
  • 11
  • 1
    Parametrised test could be an option, but have a read [here](http://stackoverflow.com/questions/9021881/how-to-run-a-test-method-with-multiple-parameters-in-mstest) about it's not easy to do with MsTest. – kayess Sep 06 '16 at 13:02
  • @kayess this is interesting – Pacchy Sep 08 '16 at 12:47

1 Answers1

3

If you want to test your "sort" methods, you should have separate unit tests for each sorting algorithm. For example

[TestMethod]
public void MergeSort_SortUnderorderedList_ShouldSortListCorrectly()
{
   // Arrange
   ISort sort = new MergeSort();

   // Act
   int[] sortedList = sort.Sort(new int[] { 4, 2, 18, 5, 19 });

   // Assert
   Assert.AreEqual(2, sortedList[0]);
   Assert.AreEqual(4, sortedList[1]);
   Assert.AreEqual(5, sortedList[2]);
   Assert.AreEqual(18, sortedList[3]);
   Assert.AreEqual(19, sortedList[4]);      
}

[TestMethod]
public void QuickSort_SortUnderorderedList_ShouldSortListCorrectly()
{
   // Arrange
   ISort sort = new QuickSort();

   // Act
   int[] sortedList = sort.Sort(new int[] { 4, 2, 18, 5, 19 });

   // Assert
   Assert.AreEqual(2, sortedList[0]);
   Assert.AreEqual(4, sortedList[1]);
   Assert.AreEqual(5, sortedList[2]);
   Assert.AreEqual(18, sortedList[3]);
   Assert.AreEqual(19, sortedList[4]);   
}

When you're writing your tests for a class which you inject a sorting algorithm into, you shouldn't be testing whether the sorting algorithm works correctly in that test. Instead, you should inject a sorting algorithm mock and test that the Sort() method is called (but not test for the correct results of the sorting algorithm in that test).

This example uses Moq to do mocking

public class MyClass
{
   private readonly ISort sortingAlgorithm;

   public MyClass(ISort sortingAlgorithm)
   {
      if (sortingAlgorithm == null)
      {
         throw new ArgumentNullException("sortingAlgorithm");
      }
      this.sortingAlgorithm = sortingAlgorithm;
   }

   public void DoSomethingThatRequiresSorting(int[] list)
   {
      int[] sortedList = this.sortingAlgorithm.Sort(list);

      // Do stuff with sortedList
   }
}

[TestClass]
public class MyClassTests
{
   [TestMethod]
   public void DoSomethingThatRequiresSorting_SomeCondition_ExpectedResult()
   {
      // Arrange - I assume that you need to use the result of Sort() in the 
      // method that you're testing, so the Setup method causes sortingMock 
      // to return the specified list when Sort() is called
      ISort sortingMock = new Mock<ISort>();
      sortingMock.Setup(e => e.Sort().Returns(new int[] { 2, 5, 6, 9 }));
      MyClass myClass = new MyClass(sortingMock.Object);

      // Act 
      myClass.DoSomethingThatRequiresSorting(new int[] { 5, 9, 2, 6 });

      // Assert - check that the Sort() method was called
      myClass.Verify(e => e.Sort(It.IsAny<int[]>));
   }
}
kayess
  • 3,384
  • 9
  • 28
  • 45
Ben Rubin
  • 6,909
  • 7
  • 35
  • 82
  • Did you notice that OP uses MsTest and not NUnit?? – kayess Sep 06 '16 at 17:55
  • @kayess What does NUnit have to do with my answer? – Ben Rubin Sep 07 '16 at 13:17
  • @ben First part of your answer is what I needed to eliminate. And Mock definitely I would use for dependencies, I am clear about that. – Pacchy Sep 08 '16 at 12:46
  • @Pacchy Why do you want eliminate the first part of my answer? If you want to test your sorting algorithms, you should write tests specifically for the sorting algorithms, and not try to test them as a side effect of a test on a different class. If you're only trying to test whether your sort is getting called (and not test the results of the sort), then mocking your `ISort` dependency will accomplish that. – Ben Rubin Sep 08 '16 at 13:03
  • @ben Yes I would want to test all sort algo but my test code is same for all sorts and expect same output. Let me rephrase the question, how can I test liskovs substitution using DI. – Pacchy Sep 09 '16 at 00:31
  • 1
    @Pacchy So you're trying to use a single unit test method to test several different sorting algorithms? Personally, I would write separate unit tests for each sorting algorithm because otherwise the test logic becomes a little obscured. Parameterized tests are meant more for specifying input values and expected values, but you could use a parameterized test to specify an integer identifier, and then create your `ISort` implementation based on that identifier. See this article https://blogs.msdn.microsoft.com/vstsqualitytools/2009/09/05/extending-the-visual-studio-unit-test-type-part-2/ – Ben Rubin Sep 09 '16 at 02:40
  • 1
    @Pacchy Or you could make a `SortFactory`, with a method that'll create all of your `ISort` implementations, and then loop your test on that method. But again, I don't recommend doing that. Unit tests should be as easy to read as possible, and conditionally creating different sorting algorithms obfuscates the test. – Ben Rubin Sep 09 '16 at 02:49
  • @ben hmmm ya got you. Thanks for the comments and link it was quite helpful. – Pacchy Sep 09 '16 at 06:02