Igor's Blog
Programming, DIY, Games, Hacks, and Tech

With JUnit 4 you can write tests that expect exceptions being thrown from the code you're testing. This is done by passing a value to the expected property for the @Test annotation. Though this is a huge step up from JUnit 3.x behaviour, it is not very flexible and doesn't let you do very accurate fail case testing.

The @Test annotation is good at checking whether a particular type of exception has been thrown and pretty much nothing else. If you need to be able to check the exception message, it's cause or even the cause message, you need to use a JUnit Rule, specifically the ExpectedException rule.

The code below is expecting JUnit 4.12 and Hamcrest 1.3 libraries. As of version 4.11 JUnit is dependant on Hamcrest 1.3 already.

To set up this rule, the following minimal code is required:
 Java
package mypackage;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
@Test
public class MyTest {
@Rule
public final ExpectedException thrown = ExpectedException.none();
}


The above sets up the rule in such a way that the no exception is expected. This is the same behaviour as if the rule was not there. I am assuming that fail/pass tests will be mixed in the same test class so expecting every test to throw an exception doesn't make sense, so we overwrite this rule for each test case that does expect an exception being thrown.

Next to set up an accurate exception check, the following additional imports are required...
 Java
import org.hamcrest.Matchers;
import static org.hamcrest.Matchers.*;


The actual code to check for the correct exception type, message and cause type and cause message is below.
 Java
@Test
public void testExceptionThrows() throws Exception {
/* check the correct exception type and message */
thrown.expect(MyException.class);
thrown.expectMessage("My exception message");
/* check exception cause type and cause message */
thrown.expectCause(Matchers.<Throwable> allOf(
instanceOf(MyOtherException.class),
hasProperty("message", containsString("My other exception message"))
));
/* remaining code that causes an exception to be thrown */
...
}


Continue reading...  

, , ,

Last week I wrote about enabling full stack trace in Maven's Surefire plugin and that got me thinking that much of the stack trace is actually not relevant. When it comes to logging, it's a waste of resources to write huge stack traces to disk that give no additional relevant information. So I thought lets see what can be done to address this.

I put together a very simple test case that used Log4J to log an exception to the console. The unfiltered output looked like this...
 Log4J unfiltered output
java.lang.RuntimeException: Numbers must be positive, please input both A and B as zero or above
at mypackage.MyClass.addPositive(MyClass.java:7)
at mypackage.MyClassTest.testAddNegative(MyClassTest.java:15)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:367)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:274)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:238)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:161)
at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:290)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:242)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:121)


That's a lot of irrelevant lines being shown! None of the junit runner or the surefire classes give me any valuable information here. So with a custom ThrowableRenderer I got the stack trace down to the essentials...
 Log4J filtered output
java.lang.RuntimeException : Numbers must be positive, please input both A and B as zero or above
at mypackage.MyClass.addPositive(MyClass.java:7)
at mypackage.MyClassTest.testAddNegative(MyClassTest.java:15)


Perfect! It's concise and gives me the exact location of the exception being thrown. All the noise is filtered out. Configuration for this is simple, something like this...
 Log4J configuration (properties file)
log4j.throwableRenderer=mypackage.BasicFilteredThrowableRenderer
log4j.throwableRenderer.filter=org.junit.,org.apache.maven.,sun.reflect.,java.lang.reflect.


The above translates to XML configuration easily too...
 Log4J configuration (XML file)
<log4j:configuration...
<throwableRenderer class="mypackage.BasicFilteredThrowableRenderer">
<param name="filter" value="org.junit.,org.apache.maven.,sun.reflect.,java.lang.reflect."/>
</throwableRenderer>
</log4j:configuration>


The main part here is setting the log4j.throwableRenderer property to the custom renderer class. This class needs to be on the classpath of course. The second property here is passed to the custom renderer by Log4J and is used to set up filters. See the setFilter() method below. I used a very simple filter mechanism, the filter string is a comma delimited string of package prefixes. Matching is done on the start of the package name only.

Continue reading...  

, ,

My growing Atari Lynx games collection was starting to run out of room and I was keeping game boxes in drawers and out of sight. This seemed to defeat the purpose of collecting the games in the first place so I decided to build a shelving unit specifically for this. The unit was designed to fit all 74 official games (it actually fits 80) and is the perfect size to hold 10 game boxes per shelf. The construction is inspired by the Ikea LAIVA bookcase.

I set out to build this in a day, from design to cutting, assembly and coating. This is the end result...
IMG_0385.jpg


The design was created using OpenSCAD. I've uploaded it for anyone to use over at Thingiverse, download the files here. The design can be customised to other game box sizes, though the default is for an Atari Lynx game box. You can also customise how many game boxes you store per shelf, how many shelves, board sizes, etc.

oscad1.png oscad2.png


Once I had the design worked out, I purchased the wood. I used meranti primarily for its colour. Since the design of the unit used only two sizes of board, all I had to get was a single piece of wide board for the shelves and the rest was for the sides and back pieces which are made from the smaller boards. My challenge was fitting it all into my car, which was not designed to transport 3m long wood boards!
IMG_0365.jpg


I used a circular saw to cut everything to size. Measuring out was easy, I set an end stop with a clamp that would give me same size cuts for each of the shelf and back pieces, then it was just a matter of cutting each one, no further measuring required there! The long side pieces were clamped together in the end and cut in one stroke, again this avoided having to measure each one individually.

IMG_0366.jpg IMG_0367.jpg


Continue reading...  

, , , ,

The Maven Surefire Plugin disables full stack trace display by default when running tests. Sometimes it is useful to see the full stack trace however, here's how you enable it.
mvn_junit1.png


As per documentations, use the trimStackTrace parameter and set it to false. Your plugin configuration for Surefire will then be something like this...
 pom.xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<trimStackTrace>false</trimStackTrace>
</configuration>
</plugin>


That's all you have to do. Next time you run tests and get an exception, the full expanded goodness or the entire stack trace will be bestowed upon you.

Continue reading...  

, , , ,
 

Recent Blog Posts

Writing accurate fail scenario unit tests with JUnit rules and exception matching

Filtering exception stack trace logging with Log4J and a custom ThrowableRenderer

Building a custom Atari Lynx game box storage shelf unit in a day

How to enable the full stack trace in Maven's Surefire plugin for JUnit testing

Twelve elements of the Burst Mining Pool interface explained

TPG FTTB settings for the Billion BiPAC 8700AXL 1600 modem router

Protecting old Atari Lynx game boxes with snug fit plastic sleeves

How to fix SoapUI javax.net.ssl.SSLHandshakeException calling WebLogic 12.2 web services on Java 8

Woolworths (WOW) shares disappeared from Computer Share Investor Centre

Connecting the Dell UltraSharp U3415W monitor to a MacBookPro via USB-C

Recent Galleries

Building a custom Atari Lynx game box storage shelf unit in a day

Protecting old Atari Lynx game boxes with snug fit plastic sleeves

Monument Valley 2 is released and does not disappoint

Space Food - Chocolate Ice Cream with Chocolate Chips

Legeod Star Wars AT-DP kit

DIY spare parts computer build with a RAIDMAX Anura case

Fake 'Lepin' brand Lego packaging

Hardwood garden bench with clear resin void filler

Fixing a 3D printer extruder that stopped heating up

Easily increase disk space in a Lenovo Ideapad 100S 14" laptop with an M.2 SSD

My Other Web Sites

Igor and Elise's Travels
Riverside Expressway Cam
300 George St Blogumentary

My Online Tools

UUID to OID Converter
Guru JSON-RPC Tester
Extrudifier Object Designer
Travel ┬ÁBlog

Blogs and Friends

Matt Moores Blog
Georgi's FlatPress Guide
Perplexing Permutations
The Security Sleuth
Ilia Rogatchevski
Travelling Fairy

Blog Activity

Blog Activity
Don't forget to
my Facebook page for more great articles!
Don't show this again