views:

303

answers:

7

I write code primarily for personal use, but I'm considering releasing an application (scientific simulation/visualization) that I originally developed for personal use.

One of my habits is to use a main method in classes for testing the operation of the class in isolation. I figure that's probably bad in someway (as are no doubt various other habits originating from self-teaching and the scientific development environment). However, it's never been a problem for self-use stuff that I've noticed.

Would you all be so kind as to confirm (or deny) that the proliferation of mains is a problem for an application released to the scientific community (the source would also be open), and if so, why?

EDIT: To play devil's advocate (okay, my advocate) relative to some of the offered answers: part of the "application use" is expected to be source modification by non-developers (the typical scientist) on a smallish scale. I know that on the receiving end, that having the tests for a class built directly into that class would be pretty straightforward for me to recognize and modify accordingly (especially if that were consistently the case for the classes). Would using something like JUnit provide similar utility, keeping in mind the audience?

ACCEPT DECISION: I think KLE's answer is the best balance of thorough and succinct, so I picked it, but I think the discussion comments in Bill's are also very helpful. I also don't understand why Johannes's answer was voted down - the "how does this piece work" perspective is very important to the scientific community coders - and while the other answers point out various reasons why separated unit tests are probably more useful than my current habit, they don't really address that use, so his answer is far from "unhelpful". Thanks to all current (and future) responders, and here's to wishing there was a way to combine multiple responses as the correct answer!

+11  A: 

Testing your class in its own main method is bad because it gives the class an extra responsibility (testing itself). Tests should go in separate classes, preferably using a testing library like JUnit.

The proliferation of mains (I like this phrase you've coined) also makes it more confusing for a developer to find the entry point to your application when they are approaching it for the first time.

Bill the Lizard
+1: All `public static void main` should be isolated into classes which does almost nothing else. All the "real" processing should be elsewhere with better API's than `main`. These "real" processing objects should be instantiated by `main`.
S.Lott
let's say the typical developer isn't actually a developer, and has little-to-no "real" world coding habits. I appreciate that your answer probably is perfectly correct for people actually employed as developers (though of course I have no idea), but do you think it's the right one for this atypical audience?
Carl
@Carl: The typical developer with a little bit of real world experience probably already follows this advice, so the atypical audience is exactly who this is for.
Bill the Lizard
So, you think a JUnit test package accompanying the application is the preferable way for scientists to be able to get into making modifications and being able to test them? As you say, that's the clearly the right answer for actual developers, but looking over the JUnit info, I'm still not convinced that is for my target audience. Why ask them to learn an additional framework for what may be a relatively minor change that they want to make/test?
Carl
The tests don't *have* to be in a unit test framework, but it's preferable. They *should* definitely be in separate classes so that the test code doesn't bloat the classes that your clients want to include in their own applications. Separating responsibilities will make your code much easier to understand, particularly to less experienced developers.
Bill the Lizard
+2  A: 

You need to use a testing tool such as JUNIT to perform testing on your classes rather than inserting the testing code into your production code.

This cleanly separates the tests from your code.

Vincent Ramdhanie
+3  A: 

It's not terrible but it's not advised for two reasons:

  1. It may allow users to do things you don't want them to do or at least give them the idea that they can do something you'd rather they didn't; and
  2. Prolific main() methods are often a poor substitute for unit tests.

It's (2) you should really concentrate on.

cletus
+6  A: 

First of all, it is great that you are writing tests. I don't really like the approach of having a main method in lots of classes in a project. I would advocate moving the test code out and using a testing framework. This keeps the source code cleaner, and if you use a consistent naming methodolgy for your test classes, it is easy to find the associated tests too.

JZeeb
A: 

There is nothing wrong with this approach per se but there is a major drawback: You must call each main() method individually to test all your code. Chances are that you won't. It's just too much hazzle. Also, when doing this, you must know which main() methods are real entry points and which ones are tests. This isn't at all obvious.

With JUnit and similar tools, you can mark code as "this is a test". This allows the tool to find all tests in your project automatically and run all of them at once. This way, chances are much higher that you'll run all tests most of the time and that bugs are caught early.

Aaron Digulla
+4  A: 

JUnit lets you have tests, just like your mains, but also:

  • a main is typically only one method, that can get real big ; if extracting small methods used only for test, there is a risk to use that methods in regular code
  • doesn't clutter the class itself with the testing methods, they are in a different class
  • allows inheritance in the test classes (main, as a static method, is impossible to inherit or reuse) ; typically, the setup before the actual test maybe pretty long, and reusing it naturally is great
  • a main has no result (success or failure), only an output ; you need to check manually the output to determine the result, and possibly understand it
  • allow execution of several tests (class, package, project, all) at once, which is required for regression testing (or you will spend your afternoon executing them one by one)
  • JUnit provide many additional features out of the box, like marking some tests as ignored, checking that a test is not too long, provide several launching UIs etc.
  • you can reuse some tests on each implementation or subclass (ex: checking for Liskov substitution), which allows you to test a lot without maintaining a lot of test code.
KLE
A: 

I would not use main methods in all classes for testing purposes too. First, to follow the separation of concerns rule (using and testing are different concerns) and because we have elegant solutions for testing.

Second, and that hasn't been mentioned so far, if each and every class has a main method, it's pretty hard to find the 'real' entry point into the application. If I see a class with a main method, I expect that this will let me 'use' the class in its intended way. I don't expect, that this will start a test case (maybe with serious side effects).

Ah, just a third aspect that comes to my mind: the main methods are always public, so user of your library is free to use these methods at any time, even from during execution of his own application. This can have terrible side-effects, especially in multi-threaded environments.

Andreas_D