I'm fairly new to this TDD and I'm lost with this at the moment.
I'm trying to use .Setup to get the product by ID of 99 and check it's actually returned in .Returns(saveProduct), which causes me the error below:
enter image description here
What am I doing wrong?
public class ProductControllerTests
{
private Mock<ICart> cartMock;
private Mock<IProductRepository> productRepositoryMock;
private Mock<IOrderRepository> orderRepositoryMock;
private Mock<IProductService> productServiceMock;
private Mock<ILanguageService> languageServiceMock;
private Mock<IStringLocalizer<ProductService>> stringLocalizerMock;
private ProductViewModel product;
private ProductController productController;
public ProductControllerTests()
{
//setup
product = new ProductViewModel();
cartMock = new Mock<ICart>();
productRepositoryMock = new Mock<IProductRepository>();
orderRepositoryMock = new Mock<IOrderRepository>();
stringLocalizerMock = new Mock<IStringLocalizer<ProductService>>();
productServiceMock = new Mock<IProductService>();
languageServiceMock = new Mock<ILanguageService>();
productController = new ProductController(productServiceMock.Object, languageServiceMock.Object);
}
[Fact]
public void CreateValidModelState() // MOCKED
{
// Act
ProductService productService = new ProductService(cartMock.Object, productRepositoryMock.Object, orderRepositoryMock.Object, stringLocalizerMock.Object);
productController = new ProductController(productService, languageServiceMock.Object);
productServiceMock.Setup(x => x.SaveProduct(product)); //It works without this?!? what's it FOR!?
//Arranje
product.Id = 99;
product.Name = "Test box";
product.Description = "The best box ever.";
product.Details = "Toss it and see if it gets back.";
product.Stock = "9000";
product.Price = "9000";
var saveProduct = productController.Create(product);
//productServiceMock.Setup(x => x.GetProductById(It.IsAny<int>())).Returns(saveProduct);
//productServiceMock.SetupGet(x => x.GetProductById(99)).Returns("Test box");
//var expectedProduct = productServiceMock.GetProduct(1);
Assert.IsType<RedirectToActionResult>(saveProduct);
}
}
}
There is a lot of room for improvement in your code snippet.
First, you create private members but then you over write the variable name with local variables.
The idea behind mocking is that when you mock an interface you can Setup its' methods to return whatever you wish them to return. So in your case
productServiceMock.Setup(x => x.GetProductById(99)).Returns(saveProduct);
the line above means that wherever in your controller you have the GetProductById(int) method is called with 99 as a parameter, the method will return the saveProduct object.
You could also write the Setup like
productServiceMock.Setup(x => x.GetProductById(It.IsAny<int>())).Returns(saveProduct);
In this case wherever in your controller the GetProductById() method is called, no matter what is the parameter passed, you will get the saveProductObject.
In this test you have written I can not see any value. What I mean is that create a controller, you create the saveProduct and then you assert it is not null. Of course it is not null, because you populated above.
It would make sense to actually use one of your controllers methods that you know that the GetByUserId() method is used. Then make an assertion upon the return object based on the methods logic.
---Update---
Imagine you have a handler
public class HandlerExample {
private IInjectedService _injectedService;
public HandlerExample(IInjectedService injectedService){
_injectedService = injectedService;
}
public int Handle(testNumber)
{
var serviceResponse = _injectedService.TestMethod(testNumber);
if(serviceResponse)
return 1;
return 2;
}
}
And your interface looks like
public interface IInjectedService
{
bool TestMethod(int testNumber);
}
I won't give any example on the implementation here because it is not relevant. Your test method would then make sense to be like
[Fact]
public void Test()
{
mockedInjectedService = new Mock<IInjectedService>();
mockedInjectedService.Setup(x => x.TestMethod(99)).Returns(true);
var handler = new Handler(mockedInjectedService.Object);
var sut = handler.Handle(99);
Assert.Equal(sut, 1);
}
sut is a convention for "system under test"
Related
I have a generic Repository with the Unit of Work pattern setup to utilize the Specification Pattern which works great but now I am trying to Unit test it and it seems my setup isn't returning anything when specifying what to return.
Repository Snippet
internal class Repository<T> : IRepository<T> where T : BaseEntity
{
protected readonly ApplicationDbContext _context;
public Repository(ApplicationDbContext context)
{
_context = context;
}
public IEnumerable<T> Find(ISpecification<T> specification = null)
{
return ApplySpecification(specification);
}
private IQueryable<T> ApplySpecification(ISpecification<T> spec)
{
return SpecificationEvaluator<T>.GetQuery(_context.Set<T>().AsQueryable(), spec);
}
}
}
Snippet of Specification
public class GetStocksForCurrentDaySpecification : BaseSpecification<Stock>
{
public GetStocksForCurrentDaySpecification() : base(x => x.DateInserted.Day == DateTime.Today.Day) { }
}
Snippet of me calling it
_unitOfWork.Repository<Stock>().Find(new GetStocksForCurrentDaySpecification());
This all works perfectly when running my code.
Here is my Unit Test where I do setup.
[Fact]
public void Job_Should_Execute()
{
var stockList = new List<Stock>();
stockList.Add(new Stock
{
Id = Guid.NewGuid(),
DateInserted = DateTime.Now,
Exchange = "ASX",
LongName = "Long Name",
MarketOpenPrice = 1.26M,
MarketPreviousClosePrice = 1.56M,
MarketPrice = 1.3M,
ShortName = "Short Name",
Symbol = "LGN"
});
var stockRepositoryMock = new Mock<IRepository<Stock>>();
stockRepositoryMock.Setup(m => m.Find(new GetStocksForCurrentDaySpecification())).Returns(stockList.ToArray());
var unitOfWorkMock = new Mock<IUnitOfWork>();
unitOfWorkMock.Setup(m => m.Repository<Stock>()).Returns(stockRepositoryMock.Object).Verifiable();
var job = new YahooStockMarketJob(new HttpClient(), unitOfWorkMock.Object, new EventPublisher(_listeners), _configuration);
job.Execute();
unitOfWorkMock.Verify();
}
When debugging, the following line returns an empty array instead of an array with one item it.
// Returns empty array
var stockRepositoryMock = new Mock<IRepository<Stock>>();
stockRepositoryMock.Setup(m => m.Find(new GetStocksForCurrentDaySpecification())).Returns(stockList.ToArray());
In your mock object you are setting up the Find method with a specific instance of GetStocksForCurrentDaySpecification. During your test you are passing a different instance of GetStocksForCurrentDaySpecification and since those are not the same it won't use that setup.
If you want your setup to work with your test you either need to use the same instance or allow any instance of the object by using It.IsAny<T>.
E.g.
// Returns empty array
var stockRepositoryMock = new Mock<IRepository<Stock>>();
stockRepositoryMock
.Setup(m => m.Find(It.IsAny<GetStocksForCurrentDaySpecification>()))
.Returns(stockList.ToArray());
I got a class which looks like below
public interface ILocationProvider
{
bool IsRequiredLocation (string type);
}
public class MyClass : IMyInterface
{
private readonly IEnumerable<ILocationProvider> _locationProvider;
public MyClass (ILocationProvider[] locationProvider)
{
_locationProvider = locationProvider;
}
public ILocationProvider ProvideRequireLocationObject(string type)
{
ILocationProvider location = _locationProvider.FirstOrDefault(x => x.IsRequiredLocation(type));
return location;
}
}
Now I am trying to write some tests for it. But I stuck passing the Mock<IEnumerable<ITransitReportCountryFlowProvider>> to constructor. Below my test code
[TestClass]
public class TMyClassTest
{
private Mock<IEnumerable<ILocationProvider>> _locationProvider = null;
private IMyInterface _myClass = null;
[TestInitialize]
public void InitializeTest ()
{
_locationProvider = new Mock<IEnumerable<ILocationProvider>>();
}
[TestMethod]
public void ProvideRequireLocationObject_Test1()
{
//Given: I have type as 'PMI'
string type = "PMI";
//When: I call MyClass object
_myClass = new MyClass(_locationProvider.Object); //wrong actual argument as the formal argument is an array of ILocationProvider
//_locationProvider.Setup(x => x.IsRequiredCountryFlow(It.IsAny<string>())).Returns(true); //how do I setup
ILocationProvider result = _myClass.ProvideRequireLocationObject(type);
//Then: I get a type of ILocationProvider in return
Assert.IsTrue(result is ILocationProvider);
}
}
Problem 1: The line _myClass = new MyClass(_locationProvider.Object) in above test class, as the constructor's formal argument is ILocationProvider[] so I cannot pass a mocking object of Mock<IEnumerable<ILocationProvider>>
Problem 2: If I change the line private readonly IEnumerable<ILocationProvider> _locationProvider; in above MyClass to private readonly ILocationProvider[] _locationProvider; I will not be able to mock it as because mock must be an interface or an abstract or non-sealed class.
Problem 3: How do I set up for _locationProvider.FirstOrDefault(x => x.IsRequiredLocation(type)); in my test method
Problem 4: How do I assert that my method ProvideRequireLocationObject is returning a type of ILocationProvider
First of all, you don’t need to mock the collection. Collections (arrays or lists) are tested well enough to trust on their implementation. Since your constructor expects an array, you need to pass an array. And the simplest way to do that is to simply pass an array. There is no reason to mock this at all.
Changing the implementation details of the class you are testing (as suggested in problem 2) will not change anything on the testing surface. Unit tests should always be independent from the internal implementation details anyway.
How do I assert that my method ProvideRequireLocationObject is returning a type of ILocationProvider
You don’t need to do that. The method has that return type, so the compiler will only accept an implementation where the method returns that type. You are guaranteed by the language that if there is a return value, then it’s of the ILocationProvider type. So you actually just need to check for null.
Taking your implementation, below is a possible way to test this. Note that you don’t actually need to mock this. You usually mock things when the actual implementation is too difficult to set up (e.g. has other dependencies) or when providing a testable implementation is too much work (e.g. an interface with lots of method but you only need one). In this case, I’m assuming that the ILocationProvider is easy to implement, so we’re going to create a test type for this:
[TestClass]
public class MyClassTests
{
[TestMethod]
public void ProvideRequireLocationObject_EmptyCollection()
{
// arrange
var providers = new ILocationProvider[] {};
var obj = new MyClass(providers);
// act
var result = obj.ProvideRequireLocationObject();
// assert
Assert.IsNull(result);
}
[TestMethod]
public void ProvideRequireLocationObject_NoRequiredLocation()
{
// arrange
var providers = new ILocationProvider[] {
new TestLocationProvider(false)
};
var obj = new MyClass(providers);
// act
var result = obj.ProvideRequireLocationObject();
// assert
Assert.IsNull(result);
}
[TestMethod]
public void ProvideRequireLocationObject_OneRequiredLocation()
{
// arrange
var providers = new ILocationProvider[] {
new TestLocationProvider(true)
};
var obj = new MyClass(providers);
// act
var result = obj.ProvideRequireLocationObject();
// assert
Assert.AreEqual(providers[0], result);
}
[TestMethod]
public void ProvideRequireLocationObject_OneRequiredLocationNotFirstInArray()
{
// arrange
var providers = new ILocationProvider[] {
new TestLocationProvider(false),
new TestLocationProvider(true),
new TestLocationProvider(false)
};
var obj = new MyClass(providers);
// act
var result = obj.ProvideRequireLocationObject();
// assert
Assert.AreEqual(providers[1], result);
}
[TestMethod]
public void ProvideRequireLocationObject_MultipleRequiredLocations()
{
// arrange
var providers = new ILocationProvider[] {
new TestLocationProvider(true),
new TestLocationProvider(true),
new TestLocationProvider(true)
};
var obj = new MyClass(providers);
// act
var result = obj.ProvideRequireLocationObject();
// assert
Assert.AreEqual(providers[0], result);
}
public class TestLocationProvider : ILocationProvider
{
public TestLocationProvider(bool isRequiredLocation)
{
IsRequiredLocation = isRequiredLocation;
}
public bool IsRequiredLocation { get; private set; }
}
}
Of course, you could expand those tests as necessary.
I believe are looking at it from the wrong angle. I think you don't need to mock the IEnumerable (Mock<IEnumerable<ITransitReportCountryFlowProvider>>) - IEnumerable has been testing front and back and besides you don't want to have to implement all its logic..
I think you should mock your own classes: Mock<ITransitReportCountryFlowProvider>
And pass a normal IEnumerable containing your mock in it
Something like:
[TestClass]
public class TMyClassTest
{
private Mock<ILocationProvider> _locationProvider = null;
private IEnumerable<ILocationProvider> _locationProviderCollection;
private IMyInterface _myClass = null;
[TestInitialize]
public void InitializeTest ()
{
_locationProvider = new Mock<IEnumerable<ILocationProvider>>();
_locationProviderCollection = new List<ILocationProvider> { _locationProvider };
}
[TestMethod]
public void ProvideRequireLocationObject_Test1()
{
//Given: I have type as 'PMI'
string type = "PMI";
//When: I call MyClass object
_myClass = new MyClass(_locationProviderCollection); //wrong actual argument as the formal argument is an array of ILocationProvider
.....
}
}
Please look at my code below, the verification always failed. Anyone can help?
public class ViewModel
{
private IMyDataService dataService = null;
public ViewModel(IMyDataService dataService)
{
this.dataService = dataService;
}
public Dictionary<string, string> filters {get; set;}
public void ProcessFilters()
{
dataService.ProcessFilters(filters);
}
}
[TestMethod]
public void ProcessFilters_Test()
{
var mockService = new Mock<IMyDataService>();
ViewModel vm = new ViewModel(mockService.Object);
Dictionary<string,string> filters = null;
vm.ProcessFilters(filters);
mockService.Verify(x=>x.ProcessFilters(filters), Times.Once);
}
According to verify-a-method-call-using-moq you have to setup the method before you can verify it:
var mockService = new Mock<IMyDataService>();
mockService.Setup(mock => mock.ProcessFilter(null));
ViewModel vm = new ViewModel(mockService.Object);
Dictionary<string,string> filters = null;
// Act
vm.ProcessFilters(filters);
// Assert
mockService.Verify(x=>x.ProcessFilters(filters), Times.Once);
Furthermore the ProcessFilters-method in your ViewModel does not expect any parameter. However you have a filters-property within your class which is not set (at least not within your provided code). So you either have to add the appropriate parameter to the method-signature or set the property:
vm.Filters = filters;
vm.ProcessFilters();
Note that the ProcessFilters method belonging to the ViewModel class does not accept any arguments, so you're not actually calling the method. If you're trying to test whether or not the ProcessFilters method belonging to the ViewModel class calls the mocked IMyDataService exactly once with a filters argument that is null, then try something like:
[TestMethod]
public void ProcessFilters_Test()
{
// Arrange.
var mock = new Mock<IMyDataService>();
var vm = new ViewModel(mock.Object);
// Act.
vm.ProcessFilters();
// Assert.
mock.Verify(s => s.ProcessFilters(null), Times.Once());
}
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);
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.
I have a bit of a perfect storm that's preventing me from testing a class. The class is a RestClient that's wrapping an in-house HttpClient (which I cannot modify). The ExecuteMethod method on the HttpClient is void. It accepts an IHttpMethod, and it modifies this object based on the response from the server. I want to mock out ExecuteMethod so that it modifies the IHttpMethod for me. I'm trying to use Callback to achieve this, but it's not working.
Here's the code that sends the request:
var httpClient = this.httpClientFactory.CreateHttpClient();
httpClient.ExecuteMethod(method);
var response = this.GetResourceResponse<T>(method.ResponseBodyAsStream.AsString());
response.ResponseHeaders = method.ResponseHeaders;
response.Status = method.StatusCode.ToString();
response.StatusCode = (int)method.StatusCode;
return response;
And here's my attempt at mocking:
var mockHttpMethod = new Mock<IHttpMethod>();
mockHttpMethod.Setup(m => m.ResponseBodyAsStream).Returns(new MemoryStream(Encoding.UTF8.GetBytes("foo")));
var modifyHttpMethod = new Action<IHttpMethod>(m =>
{
m = mockHttpMethod.Object;
});
var mockHttpClient = new Mock<IHttpClient>();
mockHttpClient.Setup(c => c.ExecuteMethod(It.IsAny<IHttpMethod>()))
.Callback<IHttpMethod>(modifyHttpMethod);
var mockHttpClientFactory = new Mock<ILegalHoldHttpClientFactory>();
mockHttpClientFactory.Setup(f => f.CreateHttpClient()).Returns(mockHttpClient.Object);
var restClient = new RestClient(mockHttpClientFactory.Object);
When the modifyHttpMethod action is executed, I observe two things, both of which I expect:
The incoming IHttpMethod (m) has the properties I expect it to have.
After assigning the mock object to m, it contains the stubbed values that I setup in my test.
However, after the callback is executed and control is returned to my application code, my method variable still has its old values that I saw in step 1 above, which causes a null reference exception when trying to read method.ResponseBodyAsStream.
Is what I'm trying to do even achievable? If so, how? Thanks!
I've replicated your setup vis a vis mocking, and can't find any issues with it:
public interface IHttpMethod
{
MemoryStream ResponseBodyAsStream { get; set; }
}
public interface IHttpClient
{
void ExecuteMethod(IHttpMethod method);
}
public class HttpClient : IHttpClient
{
#region IHttpClient Members
public void ExecuteMethod(IHttpMethod method)
{
}
#endregion
}
public class Factory
{
public virtual IHttpClient CreateHttpClient()
{
return new HttpClient();
}
}
public class ClassUnderTest
{
private readonly Factory _factory;
public ClassUnderTest(Factory factory)
{
_factory = factory;
}
public string GetResponseAsString(IHttpMethod method)
{
var myClient = _factory.CreateHttpClient();
myClient.ExecuteMethod(method);
return method.ResponseBodyAsStream.ToString();
}
}
[TestClass]
public class ScratchPadTest
{
[TestMethod]
public void SampleTest()
{
var mockHttpMethod = new Mock<IHttpMethod>();
mockHttpMethod.Setup(x => x.ResponseBodyAsStream).Returns(new MemoryStream(Encoding.UTF8.GetBytes("foo")));
var modifyHttpMethod = new Action<IHttpMethod>(m =>
{
m = mockHttpMethod.Object;
});
var mockHttpClient = new Mock<IHttpClient>();
mockHttpClient.Setup(c => c.ExecuteMethod(It.IsAny<IHttpMethod>())).Callback<IHttpMethod>(modifyHttpMethod);
var myFactoryStub = new Mock<Factory>();
myFactoryStub.Setup(f => f.CreateHttpClient()).Returns(mockHttpClient.Object);
var myCut = new ClassUnderTest(myFactoryStub.Object);
Assert.IsNotNull(myCut.GetResponseAsString(mockHttpMethod.Object));
}
}
That test passes, meaning that the memory stream is not null (otherwise an exception would be generated). The only X factor that I can see is your AsString() extension method (I'm assuming that's an extension method as intellisense doesn't show it to me on MemoryStream). Could your problem be in there?
And, by the way, what you're trying to do is almost certainly achievable with Moq.