简体   繁体   中英

Issue in unit testing and using Moq .Returns

I am new to write Unit Tests. Therefore, I have been struggling with.

I need to insert product via an external WebService. Then the WebService will return a string that is necessary to update the product afterwards.

This is my ApiController :

public class ProductController : ApiController
{
    private IProductRepository _ProductRepository;
    private IWebService _WebService;

    public ProductController(IProductRepository productRepository, IWebService webService)
    {
        _ProductRepository = productRepository;
        _WebService = webService;
    }

    public HttpResponseMessage Add(string title)
    {
        using (TransactionScope scope = new TransactionScope())
        {
            Product product = new Product
            {
                Title = title
            };

            this._ProductRepository.Add(product);

            // WebService will return a string
            string result = this._WebService.Add(product.ID, DateTime.Now); 

            product.ServiceResult = result;

            this._ProductRepository.Update(product);

            scope.Complete();
        }

        return Request.CreateResponse(HttpStatusCode.Created);
    }
}

I was wondering how should I write a unit test for this code?

I've tried to write it as follows: (with NUnit, Moq)

[TestFixture]
public class ProductControllerShould : AssertionHelper
{
    private Mock<IWebService> _WebService;
    private Mock<IProductRepository> _ProductRepository;

    [SetUp]
    public void Setup()
    {
        _WebService = new Mock<IWebService>();
        _ProductRepository = new Mock<IProductRepository>();
    }

    [Test]
    public void ReturnCreatedOnAdd()
    {
        _WebService.Setup(b => b.Add(1, DateTime.Now))
            .Returns("0");

        var controller = new ProductController(_ProductRepository.Object, 
                         _WebService.Object);

        var result = controller.Add("Lumia");

        Expect(result, Is.EqualTo(HttpStatusCode.Created));
    }
}

but when I debug the test, result in this line is null that is not correct.

string result = this._WebService.Add(product.ID, DateTime.Now);

Shouldn't this line handle the behaviour of _WebService.Add() and return "0"?

_WebService.Setup(b => b.Add(1, DateTime.Now))
                .Returns("0");

I know I write the test incorrectly but I don't know what should I do.

Thanks.

The problem here, is that you are mocking call of static method `DateTime.Now' . But "Now" in the time point of mocking and as it is called are different. Therefore your call doesn't return anything.

I could suggest 3 following ways:

1) It doesn't really matter for you, if the call was with DateTime.Now or not, in that case you could ignore the second argument:

_WebService.Setup(b => b.Add(1, It.IsAny<DateTime>())).Returns("0");

2) You want to test, that the call was with DateTime.Now . In that case i create an interface for getting DateTime.Now :

public interface IDateTimeNowProvider
{
    DateTime Now { get; }
}

public ProductController(IProductRepository productRepository,
                     IWebService webService, 
                     IDateTimeNowProvider dateTimeNowProvider)
{
    _ProductRepository = productRepository;
    _WebService = webService;
    _dateTimeNowProvider = dateTimeNowProvider;
}

In production code you use default implementation of it, that just returns D ateTime.Now . But in your test class you do mock this interface with some predefined values and you test for using this value.

var now = DateTime.Parse("2017-01-22");
var _dateTimeNowProvider = new Mock<IDateTimeNowProvider>();
var controller = new ProductController(_ProductRepository.Object, 
                        _WebService.Object, _dateTimeNowProvider.Object );
_dateTimeNowProvider.Setup(x => x.Now).Returns(now);
_WebService.Setup(b => b.Add(1,now)).Returns("0");

3) You could use special mocking framework that allows to mock static methods, as for example typemock isolator

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM