Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly mock and unit test

Tags:

I'm basically trying to teach myself how to code and I want to follow good practices. There are obvious benefits to unit testing. There is also much zealotry when it comes to unit-testing and I prefer a much more pragmatic approach to coding and life in general. As context, I'm currently writing my first "real" application which is the ubiquitous blog engine using asp.net MVC. I'm loosely following the MVC Storefront architecture with my own adjustments. As such, this is my first real foray into mocking objects. I'll put the code example at the end of the question.

I'd appreciate any insight or outside resources that I could use to increase my understanding of the fundamentals of testing and mocking. The resources I've found on the net are typically geared towards the "how" of mocking and I need more understanding of the where, why and when of mocking. If this isn't the best place to ask this question, please point me to a better place.

I'm trying to understand the value that I'm getting from the following tests. The UserService is dependent upon the IUserRepository. The value of the service layer is to separate your logic from your data storage, but in this case most of the UserService calls are just passed straight to IUserRepository. The fact that there isn't much actual logic to test could be the source of my concerns as well. I have the following concerns.

  • It feels like the code is just testing that the mocking framework is working.
  • In order to mock out the dependencies, it makes my tests have too much knowledge of the IUserRepository implementation. Is this a necessary evil?
  • What value am I actually gaining from these tests? Is the simplicity of the service under test causing me to doubt the value of these tests.

I'm using NUnit and Rhino.Mocks, but it should be fairly obvious what I'm trying to accomplish.

    [SetUp]     public void Setup()     {         userRepo = MockRepository.GenerateMock<IUserRepository>();         userSvc = new UserService(userRepo);         theUser = new User         {             ID = null,             UserName = "http://joe.myopenid.com",             EmailAddress = "[email protected]",             DisplayName = "Joe Blow",             Website = "http://joeblow.com"         };     }      [Test]     public void UserService_can_create_a_new_user()     {         // Arrange         userRepo.Expect(repo => repo.CreateUser(theUser)).Return(true);          // Act         bool result = userSvc.CreateUser(theUser);          // Assert         userRepo.VerifyAllExpectations();         Assert.That(result, Is.True,            "UserService.CreateUser(user) failed when it should have succeeded");     }      [Test]     public void UserService_can_not_create_an_existing_user()     {         // Arrange         userRepo.Stub(repo => repo.IsExistingUser(theUser)).Return(true);         userRepo.Expect(repo => repo.CreateUser(theUser)).Return(false);         // Act         bool result = userSvc.CreateUser(theUser);          // Assert         userRepo.VerifyAllExpectations();         Assert.That(result, Is.False,              "UserService.CreateUser() allowed multiple copies of same user to be created");     } 
like image 700
Ben Robbins Avatar asked Jan 24 '09 19:01

Ben Robbins


People also ask

What should you mock in unit tests?

Mocking is a process used in unit testing when the unit being tested has external dependencies. The purpose of mocking is to isolate and focus on the code being tested and not on the behavior or state of external dependencies.

What is the purpose of mocking in unit testing?

Mocking is a way to replace a dependency in a unit under test with a stand-in for that dependency. The stand-in allows the unit under test to be tested without invoking the real dependency.


1 Answers

Essentially what you are testing here is that the methods are getting called, not whether or not they actually work. Which is what mocks are supposed to do. Instead of calling the method, they just check to see if the method got called, and return whatever is in the Return() statement. So in your assertion here:

Assert.That(result, Is.False, "error message here"); 

This assertion will ALWAYS succeed because your expectation will ALWAYS return false, because of the Return statement:

userRepo.Expect(repo => repo.CreateUser(theUser)).Return(false); 

I'm guessing this isn't that useful in this case.

Where mocking is useful is when you want to, for example, make a database call somewhere in your code, but you don't want to actually call to the database. You want to pretend that the database got called, but you want to set up some fake data for it to return, and then (here's the important part) test the logic that does something with the fake data your mock returned. In the above examples you are omitting the last step. Imagine you had a method that displayed a message to the user that said whether the new user was created:

public string displayMessage(bool userWasCreated) {     if (userWasCreated)         return "User created successfully!";     return "User already exists"; } 

then your test would be

userRepo.Expect(repo => repo.CreateUser(theUser)).Return(false); Assert.AreEqual("User already exists", displayMessage(userSvc.CreateUser(theUser))) 

Now this has some value, because you are testing some actual behavior. Of course, you could also just test this directly by passing in "true" or "false." You don't even need a mock for that test. Testing expectations is fine, but I've written plenty of tests like that, and have come to the same conclusion that you are reaching - it just isn't that useful.

So in short, mocking is useful when you want to abstract away externalities, like databases, or webservice calls, etc, and inject known values at that point. But it's not often useful to test mocks directly.

like image 106
Doug R Avatar answered Oct 05 '22 22:10

Doug R