tags:

views:

187

answers:

8

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>.

A: 

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.

Gishu
A: 

Thanks for the response. But it still fails if i set the code up like:

Product p1 = new Product();
Product p2 = new Product();
var rep = new Mock<IProductRepository>();
rep.Expect(x => x.GetProductById(1)).Returns(p1);
p2 = rep.Object.GetProductById(1);
Assert.AreEqual(1, p1.ProductId);
Assert.AreEqual(1, p2.ProductId);

If i have to initialise my objects then what is the purpose of this statement?:
rep.Expect(x => x.GetProductById(1)).Returns(p1);

Thanks.

A: 

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.

Steen
There is no "default behaviour of IProductRepository" -- it's an interface; a mocking framework just does what it's told. The only way that test would pass is if a product created with the default ctor always had an ID of 1 instead of 0. Even then, it wouldn't be testing anything worthwhile.
Mark Simpson
A: 

ok, forgive me as i am new to mocking. So when i ask:
rep.Expect(x => x.GetProductById(1)).Returns(p1);

What really is happening is that the object is only being returned and the values are not set???

I dont see how mocking can be useful in this scenario? I might as well create an InMemory implementation of the Repository and to test against?

It seems overkill if i have to do something like:

Product p = new Product();
p.productId = 1;
var rep = new Mock<IProductRepository>();
rep.Expect(x => x.GetProductById(1)).Returns(p);
Assert.AreEqual(1, p.ProductId);

Am i missing the point? Thanks

A: 

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 Products added to it a default identifier (not recommended) or add an identifier to Product before adding it to the ProductRepository.

Steen
+3  A: 

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.

Ricky AH
+1  A: 

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.

Mark Simpson
+3  A: 

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:

  1. Don't mock the system under test
  2. Mock the dependencies
  3. Base your assertions on the responsibilities of the system under test, not the dependencies
Eric King
You added code to your post to make it clearer, so +1 :)
Mark Simpson