Go...
Welcome
Feeds
JavaOne 2010 - Wednesday
Posted by ccondit on 9/26/10 @ 7:04 PM :: Updated by ccondit on 9/26/10 @ 7:04 PM
Tags :: ::

More tales from JavaOne 2010 - Wednesday sessions...

JUnit Kung Fu

While JUnit has become the de facto standard for unit testing in Java, there are still many things to learn, especially with some of the new features in JUnit 4.7 and 4.8.

Test naming

Unit test names can convey a lot of useful information during testing if done right. A good test name documents the expected behavior of the test. Example: instead of BankAccountTest.testDebit(), name your test WhenABankAccountIsModified.balanceShouldDecreaseOnDebit(). NOTE: Not sure I totally agree with this one...

Test structure

Tests should be organized into three basic parts: inputs and expected outputs, action, and test assertions. Tests should be treated as production (not throwaway) code. This means refactoring regularly and keeping them clean and concise.

Hamcrest

Hamcrest is an assertion library for JUnit that makes some common assertions easier to express and read. For example, in JUnit, you might say assertEquals(10000, calculatedTax). In Hamcrest, the equivalent expression would be assertThat(calculatedTax, is(10000)), which is easier to read. It also includes more powerful matchers, and can be extended to provide your own, allowing for tests that really do follow the best practice of having only one assertion.

Parameterized tests

Parameterized tests are unit tests which are used for testing several distinct cases. To use them, you need a table of test data, and a unit tests which has parameters for each column in the table. Annotate your test class with @RunWith(Parameterized.class), and annotate a static method with @Parameters which returns test data as a collection of object arrays.

JUnit Rules

JUnit has some new functionality which involves declaring class variables with the @Rule annotation. These are snippets of code which are executed before and after each test, and augment the test framework with additional functionality. For example, the TemporaryFolder rule is used to automate the creation and deletion of temporary folders for unit tests. The Timeout rule can be used to enforce a maximum execution time for each test (useful for integration tests that may hang), and the Watchman rule allows custom code to be run on each test success or failure, which can be used to integrate with external reporting systems.

JUnit Categories

Categories are a new feature in JUnit, and are not quite ready for production use. The allow the creation of a custom hierarchy of interfaces to mark tests as belonging to particular categories. An annotation on the class (or test method) of @Category(MyInterface.class) is used to mark the test(s). Currently, this feature needs a Test Suite defined to mark tests for execution or not based on category, but should allow external tooling such as Maven and Eclipse much greater functionality in the future (Run all tests marked as IntegrationTest, for example).

Parallel tests

This is a new feature, which requires Maven and the SureFire plugin version 2.5. Simply declare a dependency on SureFire 2.5, and set a configuration item to indicate the desired level of parallelism (<parallel>methods</parallel> or <parallel>classes</parallel>). Parallel=classes is recommended for existing tests.

Other tools

Infinitest - runs unit tests after every save in Eclipse

Mockito - mocking library, tends to be less formal than EasyMock

Project Lambda - To Multicore and Beyond

This session was an overview of some of the new support for lambda expressions that will ship with Java 8 in late 2012.

Multicore processing is here, and we've hit the wall with clock cycles, so we need to adapt and work with what we have. To better support parallelism, we need good support at the library level so that people will actually use it. One of the obvious first choices is parallel operations on collections (filter, sort, map/reduce). Unfortunately, writing and using parallel libraries is clunky without some language support.

One of the biggest barriers to parallel processing is the common for loop. It is inherently serial, stateful, and often has side effects. A good parallel framework should be able to do internal iteration (exploiting parallelism), be easier to read, and support immutable collections easily.

To support this without very complex code, Java will be getting lambda expressions. A lambda expression can be thought of as shorthand for a SAM (simple abstract method) type. The Project Lambda designers recognized that Java already has a construct for functional types, namely simple abstract method (SAM) classes. These are interfaces (or abstract classes) which have a single, abstract method. Some common examples include Runnable, Comparable, etc. For compatibility with existing APIs and to avoid extending the type system further, lambda expressions will implicitly resolve to an instance of a SAM type. For example, given a Predicate<T> class with a single method boolean eval(T), the following code will declare a lambda expression which returns true for a student who graduated in 2000 and assign it to it's corresponding SAM type:

Predicate<Student> p = #{ Student s -> s.gradYear == 2000 };

Notice that the name of the method is not specified, and is not needed. Type inference is also supported, so if the "Student" type can be inferred, the lambda expression can be shortened to:

#{ s -> s.gradYear == 2000 }

Library support has yet to be finalized, but it is likely that Java will get some starter interfaces: Predicate, Filter, Extractor, Mapper, Reducer, etc.

Method references

It is expected that many lambda expressions will take the form:

#{ Person p -> p.getLastName() }

To support this common syntax, method references are supported, and can be used to shorten this expression to:

#Person.getLastName

This syntax allows the compiler to reference a method in the target type and call it on the given object automatically:

list.sortBy(#Person.getLastName);

Finally, to better support this use within collections, it would be helpful to have some new methods on the collections classes such as sortBy(), map(), filter(), etc. But, since the collections are defined in terms of interfaces, we can't extend them without breaking compatibility with third-party collection implementations. To solve this, another new language feature has been proposed which would allow interfaces to contain default implementations which defer to static methods elsewhere. This would allow these methods to be added to Collection, and defer to Collections.sortBy(), etc. This gives us the best of both worlds: a functional improvement to the language, and a backwards-compatible syntax so that existing code doesn't break. It is expected that most Collection implementations would fully implement the new methods, for reasons of performance.

This does bring up a few interesting questions though. With the new "super" interfaces, what happens if a class implements two interfaces, each of which has a default implementation of a given method? This sounds like the classic diamond problem of multiple inheritance. Also, will it be possible to extend built-in classes (via proxy perhaps) to support user-defined methods? This could be a clever way to support duck-typing, etc.

Extracting real value from Hadoop

This was a hands-on lab (the only one I had for the week), and covered some basic tasks such as writing a simple MapReduce job, interacting with the filesystem, etc.

One thing I hadn't worked with before was Hive. This is a system which allows you to map your data in HDFS onto virtual "tables" in Hive, and perform SQL queries on them. It's not very fast, but seems extremely powerful. This might be a very viable way to do ad-hoc queries of large Hadoop data sets vs. writing one-off MapReduce jobs.

Bridging Transactions from Java EE to .NET

I was hoping for a good example of two-phase commit using multiple languages, but unfortunately this talk didn't deliver. Some background was given on what two-phase commit is, the various standards on the .NET and Java sides (IEnlistmentNotification vs. XAResource), and finally interop strategies.

The conclusion seemed to imply that getting this working reliably is nearly impossible, and that in most cases you don't really need to do it anyway, even if you think you do.

Comment on this article

Comments are closed for this post.