It turns out that TestNG has built-in support for the functionality I just implemented for our JUnit tests.
Thursday, February 26, 2009
Wednesday, February 11, 2009
At work the time to execute all of our our growing set of JUnit tests has slowly crept up. In 2005 it took 25 minutes to build and test everything. Now it takes 65 minutes, most of which is spent running tests. So we decided to run the longest-running tests (defined at test classes which take > 30 seconds to execute) only once a week. So by default when one of these long-running test is run as part of a group of tests, it doesn't execute; to cause those long-running tests to run within Ant, you'd set a property to indicate this. However, we still wanted to run those tests in, say, Eclipse, because presumably someone who tries to run the test in Eclipse really wants it to run; one way to make this work is to check whether the value of the TERM environment variable is set to "dumb."
I created an annotation called IntegrationTest, which can only be applied to types, not methods. A nice enhancement could be to apply the annotation to methods, too, so that only certain long-running test methods are excluded or included as desired.
To mark test classes as long-running and I annotated each one like so:
@IntegrationTest
@RunWith(JUnit4ClassRunner.class)
package com.example.build;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.junit.runner.Description;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
public final class JUnit4ClassRunner extends BlockJUnit4ClassRunner {
private static final String TEST_TYPE_KEY = "test.type";
private static final Logger log =
Logger.getLogger(JUnit4ClassRunner.class.getName());
public JUnit4ClassRunner(Class<?> klass) throws InitializationError {
super(klass);
}
@Override
protected void runChild(FrameworkMethod method, RunNotifier notifier) {
if (shouldRun(method)) {
super.runChild(method, notifier);
} else {
log.info("Not running integration test: " + method.getMethod());
Description desc = Description.createTestDescription(
method.getMethod().getDeclaringClass(), "Integration test");
notifier.fireTestIgnored(desc);
}
}
protected boolean shouldRun(FrameworkMethod method) {
final TestType type = getTestType();
switch (type) {
case UNIT_ONLY:
return !isIntegrationTest(method);
case INTEGRATION_ONLY:
return isIntegrationTest(method);
case ALL:
return true;
default:
return true;
}
}
protected TestType getTestType() {
if (isIntegrationOnly()) {
return TestType.INTEGRATION_ONLY;
} else if (isEclipse() || isAllTests()) {
return TestType.ALL;
} else {
return TestType.UNIT_ONLY;
}
}
/**
* This is a bit of a hack, but seems to work. Eclipse sets the TERM
* environment variable to "dumb"; it's quite unlikely that a user would
* be running tests from the command line with their TERM set to "dumb."
*
* @return true if TERM is "dumb"
*/
protected boolean isEclipse() {
String value = System.getenv("TERM") == null ?
"" : System.getenv("TERM");
return value.equals("dumb");
}
protected boolean isIntegrationOnly() {
String value = System.getProperty(TEST_TYPE_KEY, "");
return value.equals("integration");
}
protected boolean isAllTests() {
String value = System.getProperty(TEST_TYPE_KEY, "");
return value.equals("all");
}
/**
* @param method The FrameworkMethod of some JUnit test method (i.e.
* a method annotated with @Test)
* @return true if the class in which the method is declared is annotated
* with @IntegrationTest
*/
protected boolean isIntegrationTest(FrameworkMethod method) {
Class<?> klass = method.getMethod().getDeclaringClass();
return klass.isAnnotationPresent(IntegrationTest.class);
}
}
Posted by ndronen at 8:25 AM 0 comments
Sunday, February 08, 2009
When I was in grad school, I cooked, but it usually wasn't very good. Hamburgers, mac and cheese, spaghetti, stuff like that. Since I finished grad school a few years ago, I haven't had to scrimp, so I haven't cooked much at all. For lunch I've usually gone to the burrito joint across the street. That changed this Christmas when I got a Cuisinart and a bunch of cook books and cooking gear. I've been making my own sorbets for a few weeks now. So far I've made batches of lime-basil, honeydew melon-mint, and raspberry-anise. And for lunch I've found two recipes that taste good reheated. Here's one of them, an Orange Sizhuan Chicken, before it goes into the fridge.
To top it off, eating this way is usually cheaper than going out, although I do have to be careful when I go to Whole Foods. Change is good.
Posted by ndronen at 2:24 PM 0 comments
Saturday, February 07, 2009
There's an article over at TPMMuckraker that got me thinking. It's a bit of a digression, but bear with me.
There seem to be two understandings of "bureaucracy," one pejorative, one objective. In the pejorative version, bureaucracy is an organization -- typically governmental, like a regulatory agency, or that pot-bellied guy who works in the zoning department -- characterized by a terrifyingly blind, sometimes petty dedication to, say, filing all of the necessary paper work for your boat license. In the objective version, which I expect is more common amongst social scientists and the like, bureaucracy is an organization characterized by a formal structure, with rules guiding how it is supposed to go about accomplishing its mission.
I prefer the objective one; it's less driven by animus and, being more generic, it lends itself to broader application. It's more useful. With that definition, a corporation is a bureaucracy, which only makes sense: it's an organization with a blind, sometimes petty dedication to profit (if, of course, you assume that corporate governance is not completely broken, which it is). Or an army: an organization with a blind, petty dedication to killing (in the national interest).
There's a stereotype that government bureaucracies are extremely inefficient, but I think that's the wrong way to look at it. They are typically just as efficient at accomplishing the goals of the organization as corporations, the military, and other institutions. They just operate under different resource constraints. A well-run military given the right resources is an efficient killing machine. A well-run technology company given the right size (e.g. IBM) or right position in the technology life cycle (e.g. the early Cisco) is an efficient profit-making machine. And a well-run regulatory agency given the right authority is an efficient regulator of whatever it's regulating.
But like it or not, that's all they do. They don't know how to handle things that conflict with their mission; when that happens, people outside the bureaucracy may have to apply force to cause it to behave correctly. Depending on the degree of asymmetry of power between the outside group and the bureaucracy, something terrible might happen before the outside group succeeds, if they succeed at all.
So, with that in mind, please, dear reader, do remember that while bureaucracies serve a useful function within their own domain, they do little else. Banks, for example, do not love you. They're financial intermediaries, run for a profit, and they want your money; they don't give a damn whether your mother just died of cancer. Actually, I take that back, they do care if your mother just died of cancer, because that may make you more vulnerable and increase the chance that they can trick you into to giving them money to which they have no rightful claim. Bastards.
Posted by ndronen at 7:29 AM 0 comments