Introducing MagicTest

If you’ve written enough JUnit 4 tests, then you should be familiar with code that looks like:

public class FooTest {

  private Foo foo;

  @Before
  public void setUp() {
    foo = new Foo();
  }

  @Test
  public void testBar() {
    assertTrue(foo.bar());
  }
}

Now, how often have you wished it were possible to simply go straight to @Test, do not pass setUp(), do not have to new Foo()?

Introducing MagicTest

So I came up with MagicTest, a parameterized base class for JUnit 4 tests that’ll let us do just that.
It lets us rewrite the above simply as:

public class FooTest extends MagicTest<Foo> {

  private Foo foo;

  @Test
  public void testBar() {
    assertTrue(foo.bar());
  }
}

It was bound to happen. I was bound to put to use my ‘hack’ on how to discover the type parameter to a generic base class.

Without further ado, here’s a simplified version of MagicTest:

public class MagicTest<T> {

  private final Class<T> classUnderTest;

  @SuppressWarnings("unchecked")
  public Base() {
    Class<?> actualClassOfSubclass = this.getClass();
    ParameterizedType parameterizedType = (ParameterizedType) actualClassOfSubclass.getGenericSuperclass();
    Type firstTypeParameter = parameterizedType.getActualTypeArguments()[0];
    this.klazz = (Class) firstTypeParameter;
  }

  @Before
  public void findAndInstantiateObjectToTest() throws Exception {
    for (Field field : this.getClass().getDeclaredFields()) {
      if (field.getType().equals(classUnderTest)) {
        T object = classUnderTest.newInstance();
        boolean accessible = field.isAccessible();
        if (!accessible) {
          field.setAccessible(true);
        }
        field.set(this, object);
        field.setAccessible(accessible);
      }
    }
  }
}
 

That really wasn’t too hard, now, wasn’t it?

Why call it MagicTest? Well, because I also happen to like using the Mockito mocking framework, and I happen to already have a unit test base class called MagicMocker. Get it? 😉

5 thoughts on “Introducing MagicTest

  1. Hi, David. That’s a very good point—and one that I’ll get to soon enough.

    Actually, this was meant to be ‘ActiveTest’, a test that not only instantiates the object, but also mocks any objects annotated with @Mock, then injects the mocks into the object under test. I guess I was just pleasantly surprised this could all be done in the first place. 🙂

    (Edit: See ActiveTest on dirty-mockito.)

  2. @david, in-line will not be repeated for every test case. that means you use the same instance for all the test cases.

    @alistair, is this just for demo? because it is a little restrictive to the subclasses. usually, you do not only instantiate in setup. you do more like initialize default values for testing like foo.setA(“a”). How can you do that in the subclasses? Have another @Before? It is possible but I think it does not guarantee which @Before will be called first (from the base class or subclass).

  3. Hi, Adrian.

    Check out my updated post on ActiveTest which takes this idea further.

    But, yes. The subclass can have its own methods annotated with @Before and JUnit will happily call the setup methods in order: Base#setUp() -> Subclass#setUp() just as you would expect.

  4. @adrian. Unless JUnit has changed recently, the runners will create a new instance of the test class for every test. It was designed that way to ensure test method independence. NUnit, on the other hand, uses the same instance of the test class.

Leave a comment