Janus007
Janus007

Reputation: 366

Testing a specific implementation with Moq

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

Answers (3)

Sergey Berezovskiy
Sergey Berezovskiy

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

k.m
k.m

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

Matteo Migliore
Matteo Migliore

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

Related Questions