Reputation:
I am using the Moq and can't seem to get my unit test to pass on what appears to be a simple mocking scenario.
Product p = new Product();
var rep = new Mock<IProductRepository>();
rep.Expect(x => x.GetProductById(1)).Returns(p);
p = rep.Object.GetProductById(1);
Assert.AreEqual(1, p.ProductId); //Assert.AreEqual failed. Expected:<1>. Actual:<0>.
Any pointers on what I'm doing wrong? My Unit test reports:-
Assert.AreEqual failed. Expected:<1>. Actual:<0>.
Upvotes: 0
Views: 1054
Reputation: 11734
I think you are missing the point of how to use mock objects in tests...
What you are doing is mocking a ProductRepository object while simultaneously testing it. That doesn't make much sense; you should not mock the object you're testing.
Let's say you have a class you want to test, ProductService, and it depends on another class, IProductRepository. When you test the ProductService, you will want to mock the dependency, IProductRepository. This allows you completely control the interaction between the class under test and its (mocked) dependency.
As you do so, your assertions will be based on what you expect the class under test, ProductService, to do. For instance, if you call the ProductService using something like productService.GetProductById(1)
, you will expect the ProductService object to call its IProductRepository method with the correct parameter exactly once: repository.GetProductById(1)
. You may also expect the ProductService to return the same object that the IProductRepository gave it. Regardless of what the repository does, that's the responsibility of the ProductService.
Having said that, your test may look something more like this:
//Arrange
int testId = 1;
var fakeProduct = new Product{ Id = testId };
var mockRepo = new Mock<IRepository>();
var productService = new ProductService(mockRepo);
mockRepo.Expect(repo => repo.GetProductById(testId)).Returns(fakeProduct);
//Act
Product returnedProduct = productService.GetProductById(testId);
//Assert
mockRepo.Verify(repo => repo.GetProductById(testId), TimesExactly(1));
Assert.AreEqual(returnedProduct.Id, fakeProduct.Id);
My syntax may be off, but hopefully the sample gets across a few points:
Upvotes: 4
Reputation: 23365
I'm looking at your code and it doesn't really look like you know what you're trying to achieve. Before writing any test, always ask the question: "What am I trying to prove, here?" The product you've created will be returned, but its ID will be the default value (0); this is expected behaviour, i.e. the mocking framework is working fine.
Test doubles (mocks, stubs, fakes, spies etc.) are used in tests to provide collaborators for the class under test. They feed interesting values into or receive calls from the class under test -- they are not the focus of the test.
Your test is currently asserting on a value returned by the test double itself. From what I can understand, either you're asking for help with an out of context code snippet (the snippet itself is just an example and not the test itself), or it is real test code that is pointless.
I've seen many a person tie themselves in knots with mocking frameworks. That's why, to begin with, I would recommend hand-writing your own test doubles. This helps you understand the interactions between the objects and form a clearer picture of what it is you wish to test. Again, this goes back to the question of "what am I trying to prove, here?".
Once you understand how to use hand-rolled test doubles to achieve a goal, you can graduate to mocking frameworks.
Upvotes: 1
Reputation: 4687
You are creating an object, setting that object as the return value for a method, and then checking if the mock is altering the object, something that the mock is not intended to do You are basically doing this:
Product getProductById(Product p) { return p; }
...
Product p = new Product();
Assert.AreEqual(1, getProductById(p).ProductID );
when creating a new Product:
Product p = new Product();
i guess that the default ProductID is 0, so the sentence:
getProductById(p).ProductID
will obviously return 0.
I'm new to mock here too, but I don't see your point. What are you trying to test? The Product class, the ProductRepository, or interactions between them? That is the first thing to think about.
Upvotes: 3
Reputation: 6849
Not exactly missing the point, Mocking is not trivial.
In your case, you are having an IProductRepository
that, I presume, is expected to hold Products
. I assume that Products
are not added to the ProductRepositort
by default (per my earlier post), and I also assume that in order to reference a Product
, it must have a productId
(which by the way you really should mutate via a mutator).
If you would like to retrieve a Product
from your ProductRepository
, I think that you should add a Product
to it through the mock framework (the moq site gives an example of registering and validating right at the top of the page), and ensure that the ProductRepostory
either gives the Product
s added to it a default identifier (not recommended) or add an identifier to Product
before adding it to the ProductRepository
.
Upvotes: 0
Reputation: 6849
I would second the view of Gishu re: the Product initialization. Unless the default behaviour of IProductRepository is to return a product referenced by the ProductId of '1', your test will fail.
And, may I add, this failure seems to be sensible behaviour. I think that you would like you ProductRepository to be empty upon initialization.
Upvotes: 0
Reputation: 136593
You're using the Product instance p once as 'the expected value' while you are setting up the expect - Returns (p) and then using the same reference to store the return value of the actual call.
As for the Assert failure, does new Product() initialize its ProductId to 1. Seems like its being set to the default value of 0 - Hence the error.
I think the Mock framework is working.
Upvotes: 0