tags:

views:

234

answers:

8

I have gone through a number posts on stackoverflow and numerous articles about Unit Tests. I am just trying to figure out that what I have understood is right.

  1. Do not test anything that does not involve logic. For example: If there is a method in the service layer which simply invokes another method in the data access layer, don't test it.

  2. Do not test basic database operations. If I have a method in the DAL which simple inserts an object in the database, say "public void save(Object object){...}" and there is no processing done on the object received from the service layer, don't test it.

  3. I don't need to validate objects at all layers. This means a certain field in an object should be not null, say the emailId in User Object, and this is verified and validated at the JSP(Using JS), I don't need to test how the DAL method behaves if it receives emailId=NULL, because ideally it should not, and this should be taken care by the JS.

What else should I be not testing?

+3  A: 

Don't test anything that can't fail.

But more to your points.

  1. This all depends on what you mean by logic. I took this approach on a mapping layer. I did not test all the boring code that copied property values from object A to object B. Bad copy paste and I had duplicated a copy and missed another. Big issue. But was it worth all the extra test code? Depends on what happens when the application fails. In this case it would have been worth the test code.

  2. Similar to point one. So Save is nice and simple, but how do you know you did the simple things right. Messing those up is just as bad as getting a bit of business logic wrong.

  3. You don't want to re-test things you already tested. But you should go beyond unit tests. Do integration and regression testing as well as unit testing. It's really nice when all the pieces work in a vacuum but blow up when put together.

Testing is a balancing act. If you truly test it all you might never get anything else done. But if you don't test it enough you spend all your time bug fixing. Where that balance point is changes. Different types of projects have different costs for failing. On some projects such as one that has understanding internal users you might be able to run loose and fast, but for how long? Eventually the untested code breaks, takes a while to find and you're not making any progress.

Best thing to do is follow true TDD. Don't test for testing's sake. Test as design technique. Test because it drives out loosely coupled code. Test because having code executed in two contexts (test and application) makes better code. Once you go down the path of TDD you don't ask what you should and shouldn't test. Testing just becomes part of writing code and not an independent activity.

Mike Two
BeowulfOF
@BeowulfOF 1. That was the point. It is an admittedly flippant response to say don't test what can't fail. It's an old rule that has a, normally, unstated corollary that everything can fail. Normally when you state the first part out loud the way you say it makes the second part clear.2. The point of the story about the copy paste code was that I had made a big mistake in not testing it. So I agree with you.
Mike Two
A: 

Wait, by JS you mean JavaScript? I assume you are referring to client side validation then? You should never assume the client validates anything when building a website. JavaScript can be disabled, pages can be altered or faked, etc.

Thorarin
Actually... http://code.google.com/p/js-test-driver/
Esko
By JS I mean JavaScript, but its more like trying to identify the responsibility of each layer, it could be the controller instead of the JS, all I want to figure out is do you need to test if a value is null at all the layers(Controller, Service and Dada Access), there would be so much of duplicate code or in other words should the receiving layer really bother if it is not receiving an invalid object when it ideally and as agreed upon should not receive an invalid object
A: 

I disagree with your points. You shouldn't write your unit tests based on how the code is written now, but to make sure that in the future, if another developer has changed some random part of the code, he can run them and get confidence that all is well.

For example, you might want to test that method that simply invokes another. After all you are only interested that the outer method works, not how it works. If the next developer changes the outer method so that is not so simple anymore, he will be missing a unit test.

This is the reason why you should use a tool like NCover to make sure that 100% of your code is executed in the unit tests!

Sklivvz
A: 

If you have stuff that already works, it may not be worth the time to write a bunch of tests around it. The caveat here is that if you need to make changes to it, or code that uses it, then those tests are invaluable.

As for not needing to test the DAL's handling of invalid input... you need to figure out what your service boundary is. This really depends. If you cannot control the client, then you need to test that your server's expectations are being met (at some layer).

Nader Shirazie
+3  A: 

Simple Answer - nothing

Complex Answer - you should not test things you do not have the time for. Testing is driven by a complex planning of the needed and affordable tests, prioritized for the most significant parts and workflows of the softwaresystem. The more time is left for testing, the more sidecases can be tested.

In UnitTesting is simply, every unit, in OOP every class has its own test. Test simply everything with values min, max, average usecases and do negativ tests - tests that have to fail if the software works correct. Test errorhandling as well.

See ITSQB for more details on that topic

BeowulfOF
A: 

I'm not unit-testing anything, because instead I want the integration and/or system tests to:

  • Cover the code
  • Be automated
  • Be used as, and to be as useful as, unit tests

For details, see Should one test internal implementation, or only test public behaviour?

Reversing your question, I suggest that the only code which you should unit test is code:

a) Which isn't going to be tested at all by integration and/or system testing (and if not, why not?)

b) Or which should, for whatever reason, be tested before integration/system testing (perhaps because of how which your project's development is partitioned to several developers in parallel)

ChrisW
+6  A: 

I'm not sure I can agree with any of the exceptions that you mention in your answer.

Methods not involving logic

Even if a method simply just delegates its implementation to an inner dependency, it is very relevant to verify that it happens. I presume that you write code for a reason, so you need to write a test that ensures that it stays that way.

Remember that one of the key benefits of unit tests are as regression test suites. Testing that an inner dependency is being correctly invoked is called Interaction Testing. Say that you have the following method:

public void Save(Entity entity)
{
    this.repository.Save(entity);
}

It is very important to test that the repository's Save method is being invoked with the correct input. Otherwise, some other developer could come along at a later date and delete that line of code and the regression test suite wouldn't alert you.

Remember: Simple things are not guaranteed to stay simple.

Not testing database operations

Do you find it inconsequential whether data is being persisted correctly in the database? If you really, truly, don't care, then you don't need to test it - otherwise you do.

If you don't test your database operations, how do you know that your data access component works?

I am not saying that you should test your ORM library, but you should test that it is being used correctly.

Not testing object in all layers

I'm not sure what you mean by this question, but if a field can be null, and this is a problem, you need to test what happens when it is, in fact, null - everywhere.

It is much more preferable, then, to design your API so that values are guaranteed not to be null.

Conclusion

You should test everything you can test. No exceptions. Simple things don't stay simple, and you need to be able to verify that code that once worked keeps working.

There are things (such as UI) that you can't unit test, and these should be abstracted away so that they contain as little logic as possible, but everything else should be tested.

Test-Driven Development (TDD) is the best way to ensure that this happens.

Mark Seemann
+1 "Test-Driven Development (TDD) is the best way to ensure that this happens."
Juri
I think you misunderstood or misquoted the OP: he isn't saying "don't test this stuff", he's saying, "don't *unit*-test it". A lot of people (like you) seem to talk about unit-testing as if unit-testing is the only kind of testing there is (and/or the only kind of automated testing), and for that reason unit-tests are over-rated.
ChrisW
@ChrisW: No, I don't think that unit testing is the only kind of testing there is, but it is the most robust and efficient kind. See http://stackoverflow.com/questions/1316101/automated-unit-testing-why-what-which/1316209#1316209 for an elaboration.
Mark Seemann
As I understand a Unit Test should not interact with the database and each method should be tested in isolation, if so, what should I write in the unit test for the snippet of code you have shown?
The repository should be an injected dependency. You can then use a Mock to verify that its Save method was correctly invoked.
Mark Seemann
"See stackoverflow.com/questions/1316101/… for an elaboration" -- Doesn't really elaborate: it just asserts (without any explanation or evidence) that unit tests are "the most efficient and robust type of automated test". IMO they're neither efficient nor robust: because unit-tests are implementation-dependent (unit-dependent), therefore they're brittle (i.e. need to be changed) if the implementation is refactored.
ChrisW
... and because they're not a substitute for integration/system testing, so if you do them then they're in addition to integration/system testing.
ChrisW
@ChrisW: Unit tests are generally more robust because you will get compilation errors when you change something that no longer works. I much prefer that to having to maintain complex deployment scripts that fail all the time and has a much longer feedback cycle. It is absolutely possible to write unit tests that are not brittle. What you are talking about is an anti-pattern called Fragile Test. I'd like to recommend the book 'xUnit Test Patterns' that explains how to avoid it.
Mark Seemann
+1  A: 

Generally if possible I would go for a TDD style. This is very hard to achieve and needs a lot of discipline, but if you have it, you would never want to return. Btw, TDD is not just about testing, but more about software design (could also be called Test-Driven-Design). Your design evolves according to your tests.

Mark did give a quite good answer to your statements of what NOT TO TEST.

I don't need to validate objects at all layers. This means a certain field in an object should be not null, say the emailId in User Object, and this is verified and validated at the JSP(Using JS), I don't need to test how the DAL method behaves if it receives emailId=NULL, because ideally it should not, and this should be taken care by the JS.

In a layered application, it may happen that you have two kind of "front-ends" / entry points for your application. One may be the normal web user interface, another may be a web-service which is consumed by some other application (possibly a desktop application). Therefore all the logic related to validation should (also) be checked in the business layer (since validations may be part of the business logic).

Juri