tags:

views:

630

answers:

11

I was reading the Joel Test 2010 and it reminded me of an issue i had with unit testing.

How do i really unit test something? I dont unit test functions? only full classes? What if i have 15 classes that are <20lines. Should i write a 35line unit test for each class bringing 15*20 lines to 15*(20+35) lines (that's from 300 to 825, nearly 3x more code).

If a class is used by only two other classes in the module, should i unit test it or would the test against the other two classes suffice? what if they are all < 30lines of code should i bother?

If i write code to dump data and i never need to read it such as another app is used. The other app isnt command line or it is but no way to verify if the data is good. Do i still need to unit test it?

What if the app is a utility and the total is <500lines of code. Or is used that week and will be used in the future but always need to be reconfiguration because it is meant for a quick batch process and each project will require tweaks because the desire output is unchanged. (i'm trying to say theres no way around it, for valid reasons it will always be tweaked) do i unit test it and if so how? (maybe we dont care if we break a feature used in the past but not in the present or future).

etc.

I think this should be a wiki. Maybe people would like to say an exactly of what they should unit test (or should not)? maybe links to books are good. I tried one but it never clarified what should be unit tested, just the problems of writing unit testing and solutions.


Also if classes are meant to only be in that project (by design, spec or whatever other reason) and the class isnt useful alone (lets say it generates the html using data that returns html ready comments) do i really need to test it? say by checking if all public functions allow null comment objects when my project doesnt ever use null comment. Its those kind of things that make me wonder if i am unit testing the wrong code. Also tons of classes are throwaway when the project. Its the borderline throwaway or not very useful alone code which bothers me.

+14  A: 

Don't get fixated on counting lines of code. Write as much test code as you need to convince yourself that every key piece of functionality is being thoroughly tested. As an extreme example, the SQLite project has a tests:source-code ratio of more than 600:1. I use the term "extreme" in a good sense here; the ludicrous amount of testing that goes on is possibly the predominant reason that SQLite has taken over the world.

Marcelo Cantos
"possibly" ... and possibly not :-)
Stephen C
Are some of these speed test? >:-) (aka not unit test ;))
acidzombie24
@acidzombie24: No, they're not.
Dolph
I am looking at it and its not clear to me, is the test cases testing the sql and database? or on each class and function they have? i cant tell if its former or latter.
acidzombie24
AFAICT, all the tests are system tests (sql and database), but developers have been very thorough in ensuring full branch coverage, with section 7 devoted to explaining it. They really went to town on this one.
Marcelo Cantos
+3  A: 

How can you do all those calculations? Ideally you should never be in a situation where you could count the lines of your completed class and then start writting the unit test from scratch. Those 2 types of code (real code and test code) should be developed and evolved together, and the only LOC metric that should really worry you in the end is 0 LOCs for test code.

cherouvim
A: 

You seem to be concerned that there could be more test-code than the code-under-test.

I think the ratios could we be higher than you say. I would expect any serious test to exercise a wide range of inputs. So your 20 line class might well have 200 lines of test code.

I do not see that as a problem. The interesting thing for me is that writing tests doesn't seem to slow me down. Rather it makes me focus on the code as I write it.

So, yes test everything. Try not to think of testing as a chore.

djna
one issue i thought was there is likely more errors in validating the error which i need to debug rather then the code i am testing which is small, good (after seeing it runs peroperly) and never needs to be touched again.
acidzombie24
also a lot of these are code specific to the project. I dont need them in other projects. so i could get away with only using specific range available in the project. Also you didnt mention if you test a class that two other classes use and only those two. Do you test the shared class or thoroughly test the two? i found the class is a helper and its only spec is to do whatever is required by the other two class. It sounds like a function but complex enough to be an object.
acidzombie24
+2  A: 

Relative LOC counts for code and tests are pointless. What matters more is test coverage. What matters most is finding the bugs.

When I'm writing unit tests, I tend to focus my efforts on testing complicated code that is more likely to contain bugs. Simple stuff (e.g. simple getter and setter methods) is unlikely to contain bugs, and can be tested indirectly by higher-level unit tests.

Stephen C
right now i only test the code i believe will give me problems. Such as escaping given a specific list of characters to escape. and code that converts data to sql queries when i expect a variety of things to be use. that and bc its shared. those two classes i used in a few projects already.
acidzombie24
+21  A: 

Here's what I'm hearing, whether you meant it this way or not: a whole litany of issues and excuses why unit testing might not be applicable to your code. In other words: "I don't see what I'll be getting out of unit tests, and they're a lot of bother to write; maybe they're not for me?"

You know what? You may be right. Unit tests are not a panacea. There are huge, wide swaths of testing that unit testing can't cover.

I think, though, that you're misestimating the cost of maintenance, and what things can break in your code. So here are my thoughts:

  • Should I test small classes? Yes, if there are things in that class that can possibly break.
  • Should I test functions? Yes, if there are things in this function that can possibly break. Why wouldn't you? Or is your concern over whether it's considered a unit or not? That's just quibbling over names, and shouldn't have any bearing on whether you should write unit tests for it! But it's common in my experience to see a method or function described as a unit under test.
  • Should I unit test a class if it's used by two other classes? Yes, if there's anything that can possibly break in that class. Should I test it separately? The advantage of doing so is to be able to isolate breakages straight down to the shared class, instead of hunting through the using classes to see if it was they that broke or one of their dependencies.
  • Should I test data output from my class if another program will read it? Hell yes, especially if that other program is a 3rd-party one! This is a great application of unit tests (or perhaps system tests, depending on the isolation involved in the test): to prove to yourself that the data you output is precisely what you think you should have output. I think you'll find that has the power to simplify support calls immeasurably. (Though please note it's not a substitute for good acceptance testing on that customer's end.)
  • Should I test throwaway code? Possibly. Will pursuing a TDD strategy get your throwaway code out the door faster? It might. Will having solid unit-tested chunks that you can adapt to new constraints reduce the need to throw code away? Perhaps.
  • Should I test code that's constantly changing? Yes. Just make sure all applicable tests are brought up to date and pass! Constantly changing code can be particularly susceptible to errors, after all, and enabling safe change is another of unit testing's great benefits. Plus, it probably puts a burden on your invariant code to be as robust as possible, to enable this velocity of change. And you know how you can convince yourself whether a piece of code is robust...
  • Should I test features that are no longer needed? No, you can remove the test, and probably the code as well (testing to ensure you didn't break anything in the process, of course!). Don't leave unit test rot around, especially if the test no longer works or runs, or people in your org will move away from unit tests and you'll lose the benefit. I've seen this happen. It's not pretty.
  • Should I test code that doesn't get used by my project, even if it was written in the context of my project? Depends on what the deliverable of your project is, and what the priorities of your project are. But are you sure nobody outside of your project will use it? If they won't, and you aren't, perhaps it's just dead code, in which case see above. From my point of view, I wouldn't feel I'd done a complete job with a class if my testing didn't cover all its important functionality, whether the project used all that functionality or not. I like classes that feel complete, but I keep an eye towards not overengineering a bunch of stuff I don't need. If I put something in a class, then, I intend for it to be used, and will therefore want to make sure it works. It's an issue of personal quality and satisfaction to me.
Owen S.
FWIW, code that is constantly changing is the most likely to break. It's just too easy to slip up and do something stupid. :-)
Donal Fellows
@Donal: I dunno about most likely, but you're right. I took out the "if it can possibly break" mantra for that one. We'll assume it can. :-)
Owen S.
"Should I test data output from my class if another program will read it? Hell yes" <-- I was thinking i will need to write a deserializing implementation which can be huge. Also it is still only being used by me /one party. So i am not convince i should write one if a program has no problems reading it for the moment or at least the output test i make. (test output != testing output)
acidzombie24
"Should I test code that doesn't get used by my project, even if it was written in the context of my project?" ... "perhaps it's just dead code" <-- Its more like this class can do A, B, and could do C but i use A and B and never ask it to handle C (say, null inputs or strings not encoded in UTF8). Should i write a test for C. The code is used by my project and not part of a lib so no one outside of the team (who wrote it) will have access to it. C could also be long inputs (>16k) when our prj only has input allowed at <=4k.
acidzombie24
also +1. (7 more to go..)
acidzombie24
Re testing data output: should be no need to write a heavy duty deserializer, simply create a "golden output" file and make sure your output matches it, using diff or the tool of your choice.
Owen S.
Wish I could give a +1 for each bullet point. :)
sarnold
@acidzombie24, if you don't need to handle UTF8, then why are you implementing support for it? It's additional complexity that makes it harder to debug the functionality you do use. Null handling is more a matter of preference -- you can check all your args for null and throw an exception, or add an assert that only fires in debug builds, or just let it fail with a null-reference or access-violation error at runtime, depending on your shop's style (and on how sure you are it won't happen in production).
Joe White
A: 

I am going to answer what I believe are the main points of your question. First, how much test-code should you write? Well, Test-Driven Development can be of some help here. I do not use it as strictly as it is proposed in theory, but I find that writing a test first often helps me to understand the problem I want to solve much better. Also, it will usually lead to good test-coverage.

Secondly, which classes should you test? Again, TDD (or more precisely some of the principles behind it) can be of help. If you develop your system top down and write your tests first, you will have tests for the outer class when writing the inner class. These tests should fail if the inner class has bugs.

TDD is also tightly coupled with the idea of Design for Testability.

My answer is not intended to solve all your problems, but to give you some ideas.

Space_C0wb0y
A: 

Some Time ago, i had The same question you have posted in mind. I studied a lot of articles, Tutorials, books and so on... Although These resources give me a good starting point, i still was insecure about how To apply efficiently Unit Testing code. After coming across xUnit Test Patterns: Refactoring Test Code and put it in my shelf for about one year (You know, we have a lot of stuffs To study), it gives me what i need To apply efficiently Unit Testing code. With a lot of useful patterns (and advices), you will see how you can become an Unit Testing coder. Topics as

  • Test strategy patterns
  • Basic patterns
  • Fixture setup patterns
  • Result verification patterns
  • Test double patterns
  • Test organization patterns
  • Database patterns
  • Value patterns

And so on...

I will show you, for instance, derived value pattern

A derived input is often employed when we need to test a method that takes a complex object as an argument. For example, thorough input validation testing requires we exercise the method with each of the attributes of the object set to one or more possible invalid values. Because The first rejected value could cause Termination of The method, we must verify each bad attribute in a separate call. We can instantiate The invalid object easily by first creating a valid object and then replacing one of its attributes with a invalid value.

A Test organization pattern which is related To your question (Testcase class per feature)

As The number of Test methods grows, we need To decide on which Testcase class To put each Test method... Using a Testcase class per feature gives us a systematic way To break up a large Testcase class into several smaller ones without having To change out Test methods.

But before reading

xUnit Test Patterns

My advice: read carefully

Arthur Ronald F D Garcia
+1  A: 

I am part of a team that have just started adding test code to our existing, and rather old, code base.
I use 'test' here because I feel that it can be very vague as to weather it is a unit test, or a system test, or an integration test, or whatever. The differences between the terms have large grey areas, and don't add a lot of value.

Because we live in the real world, we don't have time to add test code for all of the existing functionality. We still have Dave the test guy, who finds most bugs. Instead, as we develop we write tests. You know how you run your code before you tell your boss that it works? Well, use a unit framework (we use Junit) to do those runs. And just keep them all, rather than deleting them. Whatever you normally do to convince yourself that it works. Do that.

If it is easy to write the code, do it. If not, leave it to Dave until you think of a good way to do automate it, or until you get that spare time between projects where 'they' are trying to decide what to put into the next release.

Jon
+1  A: 

for java u can use junit

JUnit

JUnit is a simple framework to write repeatable tests. It is an instance of the xUnit architecture for unit testing frameworks.

* Getting Started
* Documentation
* JUnit related sites/projects
* Mailing Lists
* Get Involved

Getting Started To get started with unit testing and JUnit read the article: JUnit Cookbook. This article describes basic test writing using JUnit 4.

You find additional samples in the org.junit.samples package:

* SimpleTest.java - some simple test cases
* VectorTest.java - test cases for java.util.Vector

JUnit 4.x only comes with a textual TestRunner. For graphical feedback, most major IDE's support JUnit 4. If necessary, you can run JUnit 4 tests in a JUnit 3 environment by adding the following method to each test class:

public static Test suite() { return new JUnit4TestAdapter(ThisClass.class); }

Documentation

JUnit Cookbook
    A cookbook for implementing tests with JUnit.
Javadoc
    API documentation generated with javadoc.
Frequently asked questions
    Some frequently asked questions about using JUnit.
Release notes
    Latest JUnit release notes
License
    The terms of the common public license used for JUnit.

The following documents still describe JUnit 3.8.

The JUnit 3.8 version of this homepage
Test Infected - Programmers Love Writing Tests
    An article demonstrating the development process with JUnit.
JUnit - A cooks tour 

JUnit Related Projects/Sites

* junit.org - a site for software developers using JUnit. It provides instructions for how to integrate JUnit with development tools like JBuilder and VisualAge/Java. As well as articles about and extensions to JUnit.
* XProgramming.com - various implementations of the xUnit testing framework architecture. 

Mailing Lists There are three junit mailing lists:

* JUnit announce: [email protected] Archives/Subscribe/Unsubscribe
* JUnit users list: [email protected] Archives/Subscribe/Unsubscribe
* JUnit developer list: [email protected] Archives/Subscribe/Unsubscribe

Get Involved JUnit celebrates programmers testing their own software. As a result bugs, patches, and feature requests which include JUnit TestCases have a better chance of being addressed than those without. JUnit source code is now hosted on GitHub.

sagar
+1  A: 

One possibility is to reduce the 'test code' to a language that describes your tests, and an interpreter to run the tests. Teams I have been a part of have used this to wonderful ends, allowing us to write significantly more tests than the "lines of code" would have indicated.

This allowed our tests to be written much more quickly and greatly increased the test legibility.

sarnold
Was this an in house language or did you use something?
acidzombie24
@acidzombie24, it was an in-house language: our product was pretty niche, and there weren't existing languages to describe our problem domain. Thankfully, we could write a simple language interpreter; the test framework was more work to write. (Perhaps shell was the wrong language for the framework, but we didn't want too many dependencies on running the framework.)
sarnold
A: 

I think it's impossible to write a comprehensive guide of exactly what you should and shouldn't unit test. There are simply too many permutations and types of objects, classes, and functions, to be able to cover them all.

I suggest applying personal responsibility to the testing, and determining the answer yourself. It's your code, and you're responsible for it working. If it breaks, you have to pay the consequences of fixing the code, repairing the data, taking responsibility for the lost revenue, and apologizing to the people whose application broke while they were trying to use it. Bottom line - your code should never break. So what do you have to do to ensure this?

Sometimes unit testing can work well to help you test out all of the specific methods in a library. Sometimes unit testing is just busy-work, because you can tell the code is working based on your use of the code during higher-level testing. You're the developer, you're responsible for making sure the code never breaks - what do you think is the best way to achieve that?

If you think unit testing is a waste of time in a specific circumstance - it probably is. If you've tested the code in all of the application use-case scenarios and they all work, the code is probably good.

If anything is happening in the code that you don't understand - even if the end result is acceptable - then you need to do some more testing to make sure there's nothing you don't understand.

To me, this seems like common sense.

Erick Robertson