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.