Daniel Hansen
Daniel Hansen

Reputation: 251

Should I test the methods that are called from the method Im testing in the same test?

Lets say I have the following setup

public interface IClass1
{
  int Result(int val);
}

public interface IClass2
{
  int Validate(int val);
}

and then we have one class implementing one of these interfaces and taking the other as a parameter in the constructor.

public class Class1 : IClass1
{
  private Class2 class2;

  public Class1(IClass2 class2)
  {
    this.class2 = class2;
  }

  public int Result(int val)
  {
      return class2.Validate(val);
  }
}

If I then create a unit test for the Result method of Class1, should I also test the Validate method of Class2 in the same unit test by injecting an instance of Class2 or should this be a separate test? Am I doing integration testing if I also test the Validate method in the same test this way?

Right now I create a stub of Class2 which returns preset value for Class2.Validate and then checks that the Validate method has been called when Unit Testing Class1.Return.

Am I doing this correct?

Upvotes: 1

Views: 45

Answers (3)

StuperUser
StuperUser

Reputation: 10850

Look at the principle of isolation: http://agileinaflash.blogspot.co.uk/2012/04/is-your-unit-test-isolated.html and dirty hybrid tests http://blog.stevensanderson.com/2009/08/24/writing-great-unit-tests-best-and-worst-practises/ and research some isolation frameworks. I've had good success with Moq.

A fully isolated unit test will run only one production method. If you have two instances of classes working together, it's an integration test.

In your case:

public class Class1 : IClass1
{
  private Class2 class2;

  public Class1(IClass2 class2)
  {
    this.class2 = class2;
  }

  public int Result(int val)
  {
      return class2.Validate(val);
  }
}

Using the arrange act assert pattern one of your unit tests for Class1 would be:

[TestMethod]
public void Result_WithValidInput_CallsValidate
{
    //used the MethodUnderTest_Condition_ExpectedResult naming convention
    //Arrange
    IClass2 mockClass2;
    //TODO initialise mockClass2 with an a fake object using isolation framework, to return the relevant result to stop the code from falling over during test execution.
    Class1 class1UnderTest = new Class1(mockClass2);

    //Act
    class1UnderTest.Result(1);

    //Assert
    //TODO use methods from isolation framework to assert that mockClass2.Validate() was called with the correct argument
}

The behaviour of Class1 unit tests proves at it calls into the relevant IClass2 method properly, then the unit tests of Class2 will prove it works properly.

This tests how Class1 interacts with its Members, but this isn't an integration test, since it is against IClass2 and not the production code of Class2. The only production code being called is in Class1 and it is fully isolated from the rest of the code as a unit.

Although, strictly, you don't need to test this since Class2 is private, it's just an implementation detail of Class1.Result(), you don't need to test how Result() does something, just that it does it.

You could also consider making IClass2 a parameter to Result rather than the Class1 ctor, that way it's not being passed in if it's not needed in all methods. This can give you performance benefits if you are using DI to instantiate all of the dependent objects.

Upvotes: 0

Kjartan
Kjartan

Reputation: 19111

Short answer: No.

You should test one thing at a time.

From the perspective of Class1, class2 should just work according to IClass2, and Class1 should not have to "think about it".

Imagine that you replace the implementation of IClass2 at some point in the future - do you then want to have to update the unit tests relating to class1, just because class2 is changed? Probably not.

It's better to keep responsibilities apart, and that is a part of the reason to use Interfaces: From the perspective of Class1, You don't really know what Class2 does, or how it works - only that it is supposed to implement IClass2, and that is enough.

PS: Using testing tools like e.g. FakeItEasy, you could send a fake implementasion of IClass2, and then verify that a call to that is in fact made when the Result() method in Class1 is called.

In other words, Class1 just assumes that the implementation of IClass2 it has been given is trustworthy - all we need to do is make sure that we are in fact making use of it.

Upvotes: 1

Flynn1179
Flynn1179

Reputation: 12075

No.

Standard practice in cases like this is to pass a 'mock' (of type IClass2 in your case) into your constructor to test Class1.Result. You design the mock to return a specific value, and test that Result does return that value.

Upvotes: 0

Related Questions