tags:

views:

86

answers:

6

Let's say in my user model I have a ChangePassword method. Given an already initialised user model, it takes the new password as a parameter and does the database work to make the magic happen. The front end to this is a web form, where the user enters their current password and their desired new password. The controller then checks to see if the user's current password is correct. If so, it invokes the user model's ChangePassword method. If not, it displays an error to the user.

From what I hear you're supposed to unit test the smallest piece of code possible, but doing that in this case completely ignores the check to make sure the user entered the correct current password. So what should I do?

Should I:

A) Unit test only from the controller, effectively testing the model function too?

OR

B) Create 2 different tests; one for the controller and one for the model?

+4  A: 

When in doubt, test both. If you only test the controller and the test fails, you don't know whether the issue is in the controller or the model. If you test both, then you know where the problem lies by looking at the model's test result - if it passes, the controller is at fault, if it fails, then the model is at fault.

Amber
Not only in doubt, to be political correct, test everything. Since no one has time to test everything, test everything that is possible to test in time, decide on chance of failure or easier code metrics for what to test at last.
BeowulfOF
A: 

A) is not a unit test in my opinion since it uses more than one class (or layer). So you should really be unit-testing the model only.

dfa
It should still be tested. It just becomes an integration test instead of a unit test.
Matthew Vines
It might not be a *unit* test, but it's still a test that merits doing.
Meredith L. Patterson
Are you saying I shouldn't unit test my controller at all? How can I be sure that it will fail when the user's original password is incorrect then?
ryeguy
no I'm just saying that A) is not a unit-test, B) is a unit test. Then you can write other integration tests.
dfa
+2  A: 

A)

  • The test fails. You have a problem in either the model or the controller, or both and spend time searching through the model and controller.

B)

  • The model and controller tests fail... chances are you have a problem in the model.
  • Only the controller test fails... chances are better that the problem is not in the model, only in the controller.
  • Only the model test fails... hard to see this happening, but if it does somehow then you know the problem is in the model, not in the controller.

It's good to test both layers. It'll make finding the problem later that much easier.

digitaljoel
"Only the model test fails... hard to see this happening, but if it does somehow then you know the problem is in the model, not in the controller." -- or you have a problem with one of the tests. ;)
Amber
unfortunately, very true Dav.
digitaljoel
+1  A: 

There should be multiple tests here:

  • Verify the correct password was entered.
  • Validate the new password, e.g. doesn't match existing one, has minimum length, sufficient complexity, tests for errors thrown, etc.
  • Updating the database to the new password.

Don't forget that the tests can also help act as documentation of the code in a sense so that it becomes clear for what each part of the code is there.

JB King
+1  A: 

You might want to consider another option: Mock objects. Using these, you can test the controller without the model, which can result in faster test execution and increased test robustness (if the model fails, you know that the controller still works). Now you have two proper unit tests (both testing only a single piece of code each), and you can still add an integration test if required.

Malte Clasen
Mock objects are not necessary, depending on the way the frontend and backend work together. It is sometimes needed by unit and integrationtests, but not an testing method of its own.
BeowulfOF
That's why I wrote that the result are two unit tests. I just thought it would be useful to point out that you can actually test the controller without testing the model at the same time. If the controller depends on a model, I don't see how you would run a unit test on it all by itself.
Malte Clasen
A: 

Unit testing means to test every unit on its own, so in this case you would need to build two unit tests, one for the frontend and one for the backend.

To test the combination of both an integration test is needed, at least the ITSQB calls it like that.

If you code object oriented you usually build unit tests for every class as that is the smallest independent unit testable.

BeowulfOF