0

This is my first post!

I'm trying to write a unit test using nsubstitute but I'm finding the last bit difficult.

I've included a snippet of code below, the test fails when calling the method on the model. Is it possible to stub this method out? Similar to if it was an interface

Cheers guys! Look forward to your responses

James

My unit test attempt

public class MyTests
{
    private IModelMapper _modelMapper;

    [SetUp]
    public void Setup()
    {
        _modelMapper = Substitute.For<IModelMapper>();
    }

    [Test]
    public void GetModel_Returns_A_Model()
    {
        var result = theClass.GetModel(new Booking {CurrencyCode = ""}, null);

        **UPDATE to include assert**

        // Assert
        Assert.IsInstance<BasketModel>(result);
    }
}

Feature code

public Model GetModel(Booking booking)
{
    var model = _modelMapper.Map(booking);

    // Is it possible to stub this out?  Similar to if it was an interface
    model.FormatPricing(somethingHere);

    return model;
}

UPDATE - to illustrate return type

BasketModel model = _modelMapper.Map(booking);

UPDATE #2 - to include return

var basketModel = new BasketModel();
BasketModel model = _modelMapper.Map(booking).Returns(basketModel);
Jamie
  • 321
  • 1
  • 6
  • 18
  • What is the return type of `_modelMapper.Map(booking)`? If it is an interface, then you can stub it. – David Peden Nov 10 '14 at 23:32
  • it isn't an interface, it's a class. – Jamie Nov 10 '14 at 23:36
  • Ok, the easiest thing to do would be to implement a fake model and have your stubbed IModelMapper return it. I'd post an answer but I'm not personally familiar with nSubstitute. Also, it would be helpful to know what you are trying to test. Your test method does not contain an assertion. – David Peden Nov 10 '14 at 23:41
  • I've added the assert, simply to check the return type of the method – Jamie Nov 10 '14 at 23:50
  • can you include a link to an example please? – Jamie Nov 10 '14 at 23:51
  • Looks like you just need to add a `.Returns(...)` to your stubbed _modelMapper. See http://nsubstitute.github.io/. – David Peden Nov 10 '14 at 23:54
  • It really depends on what your `FormatPricing` implementation does I think. Is it returning anything at all? If not, you might just need to set up what ever properties it requires to continue execution, considering it is not the focus of the test you have described above. – Prabu Nov 10 '14 at 23:58
  • how do you stub a method with the model that is returned from the interface? – Jamie Nov 11 '14 at 00:22

1 Answers1

0

Can you include what test failure message you're getting?

Here is the general approach I tend to take for this kind of code. Say we're injecting the IModelMapper into the class-under-test (approximate code; I haven't tested):

[SetUp]
public void Setup()
{
    _modelMapper = Substitute.For<IModelMapper>();
    theClass = new TheClass(_modelMapper);
}
[Test]
public void GetModel_Returns_Model_From_Mapper()
{
    // Arrange
    var booking = new Booking { CurrencyCode = "" };
    var expectedModel = new BasketModel();
    _modelMapper.GetModel(booking).Returns(expectedModel);

    // Act
    var result = theClass.GetModel(booking, null);

    // Assert
    Assert.AreSame(expectedModel, result);
}

If you want to stub out BasketModel.FormatModel (that's a big "if". I would recommend using the real type if possible) then you'll want to substitute for BasketModel too.

Be careful - NSubstitute will not work with non-virtual methods, so you may want an interface for BasketModel, or just make sure to use virtual everywhere. (Again, untested code ahead)

[Test]
public void ModelReturnedShouldBeFormatted()
{
    // Arrange
    var booking = new Booking { CurrencyCode = "" };
    var expectedModel = Substitute.For<IBasketModel>();
    _modelMapper.GetModel(booking).Returns(expectedModel);

    // Act
    var result = theClass.GetModel(booking, null);

    // Assert
    expectedModel.Received().FormatModel(Arg.Any<SomethingHere>());
}

This is testing adherence to a particular contract - TheClass will call FormatModel on the BasketModel returned from the mapper. If you need to duplicate some implementation in the test (again, this is generally discouraged), you can use When..Do:

[Test]
public void FormatModel()
{
    // Arrange
    var booking = new Booking { CurrencyCode = "" };
    var expectedModel = Substitute.For<IBasketModel>();
    expectedModel
       .When(x => x.FormatModel(Arg.Any<SomethingHere>()))
       .Do(/* some action */);
    _modelMapper.GetModel(booking).Returns(expectedModel);

    // Act
    var result = theClass.GetModel(booking, null);

    // Assert
    // assertion here that depends on "some action" and result
}

Hope this helps.

David Tchepak
  • 9,826
  • 2
  • 56
  • 68