Reputation: 366
Update 1, more details
My question was hard to interpret, sorry for that....
Simple question... How do you test a specific implementation with Moq?
interface IShipping
{
int CalculateCost();
}
class TruckShipping: IShipping
{
int CalculateCost()
{
return 9;
}
}
class Shipping: IShipping
{
int CalculateCost()
{
return 5;
}
}
class CalculateSomethingMore
{
IShipping _shipping;
CalculateSomethingMore(IShipping shipping)
{
// Here I want the TruckShipping implementation!
_shipping = shipping;
}
DoCalc()
{
return _shipping.CalculateCost * 2;
}
}
Without mock it would probably look like (if you don't use DI) TEST:
var truckShipping = new TruckShipping();
var advancedCalculation = CalculateSomethingMore(truckShipping);
var result = DoCalc();
var expected = 18;
Assert.IsTrue(result == expected);
NUnit, FluentAssertions, MbUnit, xUnit, etc.. doesn't matter :)
Test: var truckShipping = Mock.Of<IShipping> .... ? I want to test the TruckShipping implementation.
and inject that into CalculateSomethingMore.
Upvotes: 1
Views: 527
Reputation: 236208
If you want to test TruckShipping implementation then you need separate tests for TruckShipping
implementation.
Currently you are testing behavior of CalculateSomethingMore
, which should return doubled value of cost, calculated by shipping. You don't care which shipping. Responsibility of CalculateSomethingMore
is asking shipping about it's cost, and doubling that cost:
Mock<IShipping> shipping = new Mock<IShipping>();
shipping.Setup(s => s.CalculateCost()).Returns(10);
CalculateSomethingMore sut = new CalculateSomethingMore(shipping.Object);
Assert.That(20, Is.EqualTo(sut.DoCalc()));
shipping.VerifyAll();
You can see, that this test uses neither 9
nor 5
as shipping cost. Why? Because you actually don't care what value it will have. Calculating shipping cost is not responsibility of class under test.
Also you need another test for your TruckShipping
implementation, which will verify, that TruckShipping
calculates shipping cost correctly (this is a responsibility of your shipping object):
TruckShipping sut = new TruckShipping();
Assert.That(9, Is.EqualTo(sut.DoCalc());
Upvotes: 1
Reputation: 31444
You use mocks to replace real dependencies (which often are too complex to instantiate) with faked, lightweight objects. Testing mocked object makes no sense at all because essentially, you'll be testing auto-generated code from some 3rd party library.
Edit:
It's still unclear why would you want to depend on concrete implementation, especially considering you're using IoC and inject IShipping
. Anyways, I think you want something that can simulate TruckShipping
, but not TruckShipping
itself. If so, it's simple:
var shippingMock = new Mock<IShipping>();
// setting up mock to return 9 makes it behave as if it was TruckShipping
shippingMock.Stub(s => s.CalculateCost()).Returns(9);
var advancedCalculation = CalculateSomethingMore(shippingMock.Object);
var result = DoCalc();
var expected = 18;
Assert.IsTrue(result == expected);
Upvotes: 1
Reputation: 923
Moq is not a testing framework, it's a mockinq framework, so it does not provide testing features.
For testing you can use SharpTestEx, for example you can write:
[TestMethod]
public void VerifyCostIsCorrect()
{
new TruckShipping()
.CalculateCost()
.Should("The TruckShipping implementation returns a wrong cost.").Be.EqualTo(9);
}
Upvotes: 1