views:

2712

answers:

14

Saw many questions asking 'how' to unittest in a specific language, but no question asking 'what', 'why', and 'when'

  • What is it?
  • What does it do for me?
  • Why should I use it?
  • When should I use it (also when not)?
  • Common pitfalls/misconceptions
+1  A: 

I would say we are here to do some of the work, even if it is pointing someone to an answer as you did. My understanding is that SO should be a place for people to ask the questions, easy or hard, that they have been unsuccessful in finding the answer themselves, for any reason.

Uber, there are a lot of resources available, and the Wikipedia article is certainly a great place to start. Once you've got a basic idea, perhaps some more specific questions can help you decide for yourself if you want to use unit testing.

palehorse
+48  A: 

Unit testing is, roughly speaking, testing bits of your code in isolation with test code. The immediate advantages that come to mind are:

  • Running the tests becomes automate-able and repeatable
  • You can test at a much more granular level than point-and-click testing via a GUI

Note that if your test code writes to a file, opens a database connection or does something over the network, it's more appropriately categorized as an integration test. Integration tests are a good thing, but should not be confused with unit tests. Unit test code should be short, sweet and quick to execute.

Another way to look at unit testing is that you write the tests first. This is known as Test-Driven Development (TDD for short). TDD brings additional advantages:

  • You don't write speculative "I might need this in the future" code -- just enough to make the tests pass
  • The code you've written is always covered by tests
  • By writing the test first, you're forced into thinking about how you want to call the code, which usually improves the design of the code in the long run.

If you're not doing unit testing now, I recommend you get started on it. Get a good book, practically any xUnit-book will do because the concepts are very much transferable between them.

Sometimes writing unit tests can be painful. When it gets that way, try to find someone to help you, and resist the temptation to "just write the damn code". Unit testing is a lot like washing the dishes. It's not always pleasant, but it keeps your metaphorical kitchen clean, and you really want it to be clean. :)

Edit: One misconception comes to mind, although I'm not sure if it's so common. I've heard a project manager say that unit tests made the team write all the code twice. If it looks and feels that way, well, you're doing it wrong. Not only does writing the tests usually speed up development, but it also gives you a convenient "now I'm done" indicator that you wouldn't have otherwise.

Rytmis
+16  A: 

I don't disagree with Dan (although a better choice may just be not to answer)...but...

Unit testing is the process of writing code to test the behavior and functionality of your system.

Obviously tests improve the quality of your code, but that's just a superficial benefit of unit testing. The real benefit are to

  1. Make it easier to change the technical implementation while making sure you don't change the behavior (refactoring). Properly unit tested code can be aggressively refactored/cleaned up with little chance of breaking anything.
  2. Give developers confidence when adding behavior or making fixes.
  3. Document your code
  4. Indicate areas of your code that are tightly coupled. It's hard to unit test code that's tightly coupled
  5. Provide a means to use your API and look for difficulties early on
  6. Indicates methods and classes that aren't very cohesive

You should unit test because its in your interest to deliver a maintainable and quality product to your client.

I'd suggest you use it for any system, or part of a system, which models real-world behavior. In other words, it's particularly well suited for enterprise development. I would not use it for throw-away/utility programs. I would not use it for parts of a system that are problematic to test (UI is a common example, but that isn't always the case)

The greatest pitfall is that developers test too large a unit, or they consider a method a unit. This is particularly true if you don't understand Inversion of Control - in which case your unit tests will always turn into end-to-end integration testing. Unit test should test individual behaviors - and most methods have many behaviors.

The greatest misconception is that programmers shouldn't test. Only bad or lazy programmers believe that. Should the guy building your roof not test it? Should the doctor replacement a heart valve not test the new valve? Only a programmer can test that his code does what he intended it to do (QA can test edge cases - how code behaves when its told to do things the programmer didn't intend, and the client can do acceptance test - does the code do what what the client paid for it to do)

Karl Seguin
+9  A: 

Sorry for asking such a "dumb" question.

I was looking for a human-ized real world answer, not an dry encyclopedia answer. I hoped it would entice other quality links other then a link to en:wp, as not every knowledgeable person has taken time to add to 1 wiki page on the mattter.

And figured it would be a good title to show up if you went looking at the "unit-testing" tag here from another article (which I did)

Uberfuzzy
+2  A: 

This is my take on it. I would say unit testing is the practice of writing software tests to verify that your real software does what it is meant to. This started with jUnit in the Java world and has become a best practice in PHP as well with SimpleTest and phpUnit. It's a core practice of Extreme Programming and helps you to be sure that your software still works as intended after editing. If you have sufficient test coverage, you can do major refactoring, bug fixing or add features rapidly with much less fear of introducing other problems.

It's most effective when all unit tests can be run automatically.

Unit testing is generally associated with OO development. The basic idea is to create a script which sets up the environment for your code and then exercises it; you write assertions, specify the intended output that you should receive and then execute your test script using a framework such as those mentioned above.

The framework will run all the tests against your code and then report back success or failure of each test. phpUnit is run from the Linux command line by default, though there are HTTP interfaces available for it. SimpleTest is web-based by nature and is much easier to get up and running, IMO. In combination with xDebug, phpUnit can give you automated statistics for code coverage which some people find very useful.

Some teams write hooks from their subversion repository so that unit tests are run automatically whenever you commit changes.

It's good practice to keep your unit tests in the same repository as your application.

Flubba
A: 

Unit-testing is the testing of a unit of code (e.g. a single function) without the need for the infrastructure that that unit of code relies on. i.e. test it in isolation.

If, for example, the function that you're testing connects to a database and does an update, in a unit test you might not want to do that update. You would if it were an integration test but in this case it's not.

So a unit test would exercise the functionality enclosed in the "function" you're testing without side effects of the database update.

Say your function retrieved some numbers from a database and then performed a standard deviation calculation. What are you trying to test here? That the standard deviation is calculated correctly or that the data is returned from the database?

In a unit test you just want to test that the standard deviation is calculated correctly. In an integration test you want to test the standard deviation calculation and the database retrieval.

Guy
A: 

I have a question....

Unit testing is great and I agree it needs to be done BUT.....

What do you do if you are given a pile of crap and seem like you are stuck in a perpetual state of cleanup that you know with the addition of any new feature or code can break the current set because the current software is like a house of cards?

How can we do unit testing then?

Just do your best. If you can show via testing that SOMETHING is correct, you're better off than you were before, right?
drhorrible
A: 

I went to a presentation on unit testing at FoxForward 2007 and was told never to unit test anything that works with data. After all, if you test on live data, the results are unpredictable, and if you don't test on live data, you're not actually testing the code you wrote. Unfortunately, that's most of the coding I do these days. :-)

I did take a shot at TDD recently when I was writing a routine to save and restore settings. First, I verified that I could create the storage object. Then, that it had the method I needed to call. Then, that I could call it. Then, that I could pass it parameters. Then, that I could pass it specific parameters. And so on, until I was finally verifying that it would save the specified setting, allow me to change it, and then restore it, for several different syntaxes.

I didn't get to the end, because I needed-the-routine-now-dammit, but it was a good exercise.

SarekOfVulcan
A: 

What do you do if you are given a pile of crap and seem like you are stuck in a perpetual state of cleanup that you know with the addition of any new feature or code can break the current set because the current software is like a house of cards?

How can we do unit testing then?

You start small. The project I just got into had no unit testing until a few months ago. When coverage was that low, we would simply pick a file that had no coverage and click "add tests".

Right now we're up to over 40%, and we've managed to pick off most of the low-hanging fruit.

(The best part is that even at this low level of coverage, we've already run into many instances of the code doing the wrong thing, and the testing caught it. That's a huge motivator to push people to add more testing.)

Adam V
+3  A: 

Chipping in on the philosophical pros of unit testing and TDD here are a few of they key "lightbulb" observations which struck me on my tentative first steps on the road to TDD enlightenment (none original or necessarily news)...

  1. TDD does NOT mean writing twice the amount of code. Test code is typically fairly quick and painless to right and is a key part of your design process and critically:

  2. TDD helps you to realise when to stop coding! Your tests give you confidence that you've done enough for now and can stop tweaking and move on to the next thing.

  3. The tests and the code work together to achieve better code. Your code could be bad / buggy. Your TEST could be bad / buggy. In TDD you are banking on the chances of BOTH being bad / buggy being fairly low. Often its the test that needs fixing but that's still a good outcome.

  4. TDD helps with coding consipation. You know that feeling that you have so much to do you barely know where to start? It's Friday afternoon, if you just procrastinate for a couple more hours... TDD allows you to flesh out very quickly what you think you need to do, and gets your coding moving quickly. Also, like lab rats, I think we all respond to that big green light and work harder to see it again!

  5. In a similar vein, these designer types can SEE what they're working on. They can wander off for a juice / cigarette / iphone break and return to a monitor that immediately gives them a visual cue as to where they got to. TDD gives us something similar. It's easier to see where we got to when life intervenes...

  6. I think it was Fowler who said: "Imperfect tests, run frequently, are much better than perfect tests that are never written at all". I interprate this as giving me permission to write tests where I think they'll be most useful even if the rest of my code coverage is woefully incomplete.

  7. TDD helps in all kinds of surprising ways down the line. Good unit tests can help document what something is supposed to do, they can help you migrate code from one project to another and give you an unwarranted feeling of superiority over your non-testing colleagues :)

This presentation is an excellent introduction to all the yummy goodness testing entails:

reefnet_alex
+1 for "your tests might be wrong"! I'd give another +1 if I could for using tests as markers - leaving yourself a failing test on a Friday afternoon's an awesome way to get you quickly into the groove come Monday morning.
Frank Shearar
A: 

Test Driven Development has sort of taken over the term Unit Test. As an old timer I will mention the more generic definition of it.

Unit Test also means testing a single component in a larger system. This single component could be a dll, exe, class library, etc. It could even be a single system in a multi-system application. So ultimately Unit Test ends up being the testing of whatever you want to call a single piece of a larger system.

You would then move up to integrated or system testing by testing how all the components work together.

bruceatk
+3  A: 

I use unit tests to save time.

When building business logic (or data access) testing functionality can often involve typing stuff into a lot of screens that may or may not be finished yet. Automating these tests saves time.

For me unit tests are a kind of modularised test harness. There is usually at least one test per public function. I write additional tests to cover various behaviours.

All the special cases that you thought of when developing the code can be recorded in the code in the unit tests. The unit tests also become a source of examples on how to use the code.

It is a lot faster for me to discover that my new code breaks something in my unit tests then to check in the code and have some front-end developer find a problem.

For data access testing I try to write tests that either have no change or clean up after themselves.

Unit tests aren’t going to be able to solve all the testing requirements. They will be able to save development time and test core parts of the application.

Leah
+2  A: 

How has no answer mentioned Testivus yet? All you need to know right there :)

MetroidFan2002
+3  A: 

I was never tought unit testing at university, and it took me a while to "get" it. I read about it, went "ah, right, automated testing, that could be cool I guess", and then I forgot about it.

It took quite a bit longer before I really figured out the point: Let's say you're working on a large system and you write a small module. It compiles, you put it through it's paces, it works great, you move on to the next task. Nine months down the line and two versions later someone else makes a change to some seemingly unrelated part of the program, and it breaks the module. Worse, they test their changes, and their code words but they don't test your module; hell, they may not even know your module exists.

And now you've got a problem: broken code is in the trunk and nobody even knows. The best case is an internal tester finds it before you ship, but fixing code that late in the game is expensive. And if no internal tester finds it...well, that can get very expensive indeed.

The solution is unit tests. They'll catch problems when you write code - which is fine - but you could have done that by hand. The real payoff is that they'll catch problems nine months down the line when you're now working on a completely different project, but a summer intern thinks it'll look tidier if those parameters were in alphabetical order - and then the unit test you wrote way back when fails, and someone throws things at the intern until he changes the parameter order back. That's the "why" of unit tests. :-)

Cody Hatch