Showing posts with label java. Show all posts
Showing posts with label java. Show all posts

Sunday, August 9, 2009

Finished Profiler4j Fork

Some days ago, I started on my fork of the Profiler4j project. Now I'm done and the fork can be used. There even is documentation.

Monday, July 20, 2009

org.mockito.exceptions.misusing.UnfinishedStubbingException

Mockito is a great tool for mocking. It also showed me how readable Java code can look if done right (readable for Java code that is, of course). But every once in a while Mockito produces one of those very informative error messages and I spend some time figuring out how to avoid the mis-behaving code. (Run-time code generation ftw)

Lets have a look at an example. It "works" with Mockito 1.7. We start with the code to be tested. Have a look at the following class definition, with Opera and Hero being dummy classes. (Full source code available below)

static class CoverCreator {
public Cover print(Opera opera) {
// magic
opera.getHero().prepareToPrint();
// magic
return new Cover();
}
}

Intuitively, CoverCreator produce a cover for a given opera. To be able to do that, it needs, among other things, call a prepare method which returns void.

To test this behavior we define a helper method that creates a mocked opera and stuffs it with another mock of type Hero. Since it is used by many tests, we don't stub any "real" methods here.

private Opera createMockedOpera() {
Opera opera = mock(Opera.class);

Hero hero = mock(Hero.class);
when(opera.getHero()).thenReturn(hero);

return opera;
}

The test in question creates such a mocked Opera object and stubs the prepareToPrint() Method (to do nothing, in this case).

public void testFails() {
// setup
Opera opera = createMockedOpera();
doNothing().when(opera.getHero()).prepareToPrint(); <--

// run
Cover cover = new CoverCreator().print(opera);

// assert
assertNotNull("Correct input must result in a cover object!", cover);
}

When run, this test produces the following UnfinishedStubbingException. The line pointed to by the exception is the highlighted one.

org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unifinished stubbing detected!
E.g. toReturn() may be missing.
Examples of correct stubbing:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod();
Also make sure the method is not final - you cannot stub final methods.
at UnfinishedStubbingTest.testFails(UnfinishedStubbingTest.java:47)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at junit.framework.TestCase.runTest(TestCase.java:164)
at junit.framework.TestCase.runBare(TestCase.java:130)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:120)
at junit.framework.TestSuite.runTest(TestSuite.java:230)
at junit.framework.TestSuite.run(TestSuite.java:225)
at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)


This is not so great, especially since it is not immediately clear, why. The argument provided to the method is definitely a mock. This can be verified in the debugger or by extracting the result of opera.getHero() manually.

The problem is that opera in this case is a mock also. At this point, mockito is somehow confused by the mocked call, which is very similar to the usual stubbing pattern when(some_mock.call()).thenReturn(some_return_value).

So, what needs to be done is to extract the mock before. And everything is fine.

public void testSucceeds() {
// setup
Opera opera = createMockedOpera();
Hero hero = opera.getHero();
doNothing().when(hero).prepareToPrint();

// run
Cover cover = new CoverCreator().print(opera);

// assert
assertNotNull("Correct input must result in a cover object!", cover);
}

Full source code here: java, pretty printed html

Profiler4j fork

I've begun a fork of Profiler4j on github to add a few exporting and visualizing features I need.

Long live open source - as in free - software ...

Tuesday, June 16, 2009

Handy Tools for Java Development

Some links to basic, but nevertheless interesting tools for java development, especially in larger projects. All of them are available as eclipse plugins.

Code quality

FindBugs: Very useful to detect (potential) bugs, deficiencies and general ugliness.

UCDetector finds code that is not referenced and therefore (possibly) not used anymore. (Even points out that something is referenced by testing code, only.) Works on classes as well as on more fine-grained levels. Also proposes to reduce visibility of structures, e.g. to make things private.

EclEmma is a java code coverage tool. This becomes a powerful utility in combination with JUnit-Tests. Running the unit-test using the coverage starter lets EclEmma analyze the tested code. After the tests complete, the code covered by your tests is visualized in the editor window. (Green for covered, red for not.) This lets you easily identify code fragments that no test ever "visited".

Testability Explorer: Reports on the testability of your classes in terms of a number. Gives a quick overview of which classes definitely need some work.

Debugging

VisualVM: Stand-alone program that allows you to connect to a running java-prog and dump its heap. The latter can then be opened for analysis, e.g. by the Memory Analyzer (see below). An interesting feature is to let VisualVM automatically dump the heap in case the program under scrutiny receives an OutOfMemoryError. This way you don't need to sit next to the screen all the time, until the memory leak occurs.

Note that you need to use the *Java 6 JDK*. Both VisualVM and the inspected program need to use it. If your default is another Java installation, then you need to point to the Java 6 JDK using the command-line argument "--jdkhome".

Memory Analyzer (MAT) does just that: It loads a heap file that might have been created by VisualVM for instance. Then, it tries to detect classes responsible for a memory leak and more. See the home page for details.

Management

Projectset: Manages dependencies between multiple projects. Takes versions / branches of VCSs into account. The adaptor to CVS is included, the ones for SVN are available from the project's homepage.

Sunday, November 16, 2008

Java Discussion

Using some slides, I prepared a discussion at work on some features and properties of Java 1.5. There are lots of features that I believe a professional developer ought to be at least aware of. Some to be avoided, others to be used just when the circumstances are right.