Hi I am new to Moq framework and have some questions about how to use it. I will give an example and hope for answers.
I have two classes, an interface and and an implementation:
public class Vehicle{
public string RegistrationNumber {get; set;}
public long VehicleIdentifier { get; set; }
public Tyre TyreSpecification { get; set; }
}
public class Tyre {
public long NumberOfTyres {get; set;}
public long TyreSize { get; set;}
}
public interface ISelecter {
Vehicle GetVehicleByRegistrationNumber(string registrationNumber);
Tyre GetTyreSpecification(long vehicleIdentifier);
}
public class Selecter : ISelecter
{
public Vehicle GetVehicleByRegistrationNumber(string registrationNumber)
{
var vehicle = 'Database will give us the vehicle specification';
//Then we do things with the vehicle object
//Get the tyre specification
vehicle.TyreSpecification = GetTyreSpecification(vehicle.VehicleIdentifier);
return vehicle;
}
public Tyre GetTyreSpecification(long vehicleIdentifier)
{
var tyre = 'external manufacture system gets the tyre specification';
//Then do thing with the tyre before returning the object
return tyre;
}
}
I want to write two tests for those methods. The problem is when I write the test for GetVehicleByRegistrationNumber
I do not know how to mock the method call to GetTyreSpecification
.
The test methods look like this:
[TestClass]
public class SelecterTest
{
[TestMethod]
public void GetTyreSpecification_test()
{
//Arrange
var tyre = new Tyre { NumberOfTyres = 4, TyreSize = 18 };
var mockSelecter = new Mock<ISelecter>();
mockSelecter.SetUp(s=>s.GetTyreSpecification(It.IsAny<long>())).Returns(tyre);
//Act
var tyreSpec = mockSelecter.Object.GetTyreSpecification(123456);
//Assert
Assert.IsTrue(tyreSpec.NumberOfTyres == 4 && tyreSpec.TyreSize == 18);
}
[TestMethod]
public void GetVehicleByRegistrationNumber_test()
{
//Arrange
var vehicle= new Vehicle { VehicleIdentifier = 123456, RegistrationNumber = ABC123, TyreSpecification = new Tyre { Tyresize = 18, NumberOfTyres = 4 }};
var mockSelecter = new Mock<ISelecter>();
mockSelecter.SetUp(s=>s.GetVehicleByRegistrationNumber(It.IsAny<string> ())).Returns(vehicle);
//Act
var vehicle = mockSelecter.Object.GetVehicleByregistrationNumber(123456);
//Assert
Assert.IsTrue(vehicle.Registrationnumber == "ABC123";
}
}
In the test method GetVehicleByRegistrationNumber_test
how do I mock the call to getTyreSpecification
?
Best Answer
The focus on mocking the class under test has blinded you to the actual problem.
From the comments in the class under test...
you actually expose two dependencies that should be injected into the class.
For the purpose of explaining this answer lets say those dependencies looked like this.
That would mean that the
Selecter
would need to be refactored to expect those dependencies.From there it would then be a matter of mocking only the dependencies explicitly needed to test the behavior of the method under test.
selecter.GetTyreSpecification
has no need to access the database so there is no reason to mock and inject it for the test.selecter.GetVehicleByRegistrationNumber
however needs to be able to get the tyre specification from the other method so this test would need both dependencies mocked in order for it to be exercised to completion.Now with that out of the way, if for example the
Selecter
class had theGetVehicleByRegistrationNumber
as avirtual
method,There is a way you can use moq to stub the subject under test and mock that method for testing. This is not always the best design and is considered a code smell. However there are situations where you will end up in this particular scenario.
In the above example, when
selecter.Object.GetVehicleByRegistrationNumber(registrationNumber)
is called, the baseSelecter
wrapped by the mock will be called, which in turn will then call the mockedGetTyreSpecification
that was overridden by the setup on the mocked subject under test.You tend to see this when testing abstract classes with implemented members that have dependencies on abstract members.