Infinitest for Java, have you tried it? 10
Background
About 2 years ago, I was working with Ben Rady and he demonstrated something he was working on at the time: Infinitest. As often I am, I was a little interested but mostly skeptical – don’t know if that came across or not.Since then he and others (e.g., Rod Coffin have made amazing strides and created plugins for both Eclipse and IntelliJ.
Taking it for a test run
Earlier this month, I finally decided to give it a test drive. When I made that announcement, Ben made the following (bold?) statement:For me, using Infinitest is as different from TDD as TDD is from not testing
So is that true? Is using a continuous test execution tool as different from not using one as using TDD is from not testing? I’m not sure I’m there yet. However, I will say my brain is having some difficulty getting used to the cool feedback.
Here are two recent experiences I had using it.
Classpath Issues
Back at the end of 2006 I wrote a class on using JPA and EJB 3. I’ve not really done much to update that material in some years but recently I had an email from someone trying to work through the first tutorial with little success. Over the past few years there’s been some bit-rot. The embeddable container is not really up to date, EJB 3.1 includes an embeddable container as part of its spec, Hibernate has been updated, etc. So I spent a few hours tracking down updated jar files and building my classpath. I had already installed Infinitest and I noticed as added I something to my classpath, Infinitest would kick off and show a stack trace (my code was doing that in a @Before method). So I sped up what I was doing:- I directly edited the .classpath file in Eclipse
- Saved what I was doing
- Waited about a second
- Noticed the new stack trace
- Found the next jar file I needed to add
- Repeat until tests passed.
Might sound like a bit of overkill, but in the end I built a classpath from scratch and I ended up adding 13 jar files. So it saved some time.
Note, I wasn’t looking for this. I had only installed Infinitest the day before so this was unexpected and welcome! Oh, and before my @Before method was handling the exception properly, Infinitest showed that the code had a problem (it was in the @After with a null pointer exception), which it indicated as an error like a syntax error or a validation error. Nice!
Using Mockito
I’ve recently been using Mockito. You can review a previous blog entry for that example. Today we’re holding the first coding dojo at the recently opened OkC CoCo. Last night I started working on the next problem I want to use for the next dojo. It involves practicing using a mockist approach. I set up my classpath, started writing tests and immediately I noticed what looked like a syntax error on the verification step of my first unit test. I was confused thinking I had an actual syntax error since I’m not quite to the point of touch-typing Mockito based tests (I did update Eclipse so I could more easily find the static imports).Next, I updated my test to use the @Mock annotation. I removed the hand-written initialization and immediately I noticed a “syntax” error – null pointer exception. I was immediately (OK 1 second later) showed the impact of removing a single line of code. I added the missing line to auto-initialize the @Mock annotated fields but I did it incorrectly, so the error remained. I finally got the line correct and the “syntax error” went away.
Observations
Wow. That’s what I have to say so far. I’m not entirely sure the before and after of using Infinitest is the same size as moving from not testing to using TDD. Maybe it’s the same as moving from being Test Infected to practicing TDD. I was Test Infected several years before I practiced TDD.I was also about as skeptical that moving to TDD from being Test Infected was useful. I was wrong. History tends to repeat itself, so I’m guessing, based on my initial resistance, that this is the future.
Embrace it.
Mockito Example (Java Mocking Framework) 112
Recently I was lamenting how much I liked Moq for C# and its API. I like that is uses lambdas and generics and I think both the interface and general approach are great.
Someone I follow on twitter, @tieTYT, suggested that I should give Mockito a try. It is a mocking library for Java, written by Szczepan Faber and friends.
Well I gave it a try and I found it to be an excellent Mocking framework similar in spirit to Moq and it worked well while not requiring lambdas.
I was in a mood, so I went ahead and wrote a quick tutorial. While it is still under construction, you can have a look at it. If you work through it, you’ll:- Develop something using TDD.
- Using a mockist approach
- Use Inversion of Control
- Refactor code to use the GoF state pattern
- Refactor code to use the GoF Template Method Pattern
- Fix the code to avoid violation of the Liskov substitution principle (this is in there though not currently emphasized)
- Fix the code to avoid violation of the Dependency Inversion Principle.
- And as a side benefit, by using a TDD approach you’ll naturally avoid violating the Law of Demeter (though you will introduce some feature envy).
Have fun and please comment. You can also view a printable version.
FWIW, I learned Mockito and wrote this tutorial in about a single work day, so it was pretty easy to pick up and use. I suspect my recent experience with Moq gave me the mental model and then it was just a matter of syntax.
Strict Mocks and Characterization Tests 15
This week I worked with a great group in Canada. This group of people had me using Moq for the first time and I found it to be a fine mocking tool. In fact, it reminded me of why I think the Java language is now far outclassed by C# and only getting more behind (luckily the JVM has many languages to offer).
One issue this group is struggling with is a legacy base with several services written with static API’s. These classes are somewhat large, unwieldy and would be much improved with some of the following refactorings:- Replace switch with polymorphism
- Replace type code with strategy/state
- Introduce Instance Delegator
- Use a combination of template method pattern + strategy and also strategy + composite
This is actually pretty standard stuff and this group understands the way forward. But what of their existing technical debt?
Today we picked one method in particular and attempted to work our way through it. This method was a classic legacy method (no unit tests). It also had a switch on type and then it also did one or more things based on a set of options. All of this was in one method.
If you read Fowler’s Refactoring Book, it mentions a combination of encapsulating the type code followed by replacing switch with polymorphism for the first problem in this method (the switch). We were able to skip encapsulating the type code since we wanted to keep the external API unchanged (legacy code).
So we first created a base strategy for the switch and then several empty derived classes, one for each of the enums. This is a safe legacy refactoring because it only involved adding new code.
Next, we created a factory to create the correct strategy based on the type code and added that to the existing method (we also added a few virtual methods). Again, a safe refactoring since it only involved adding effectively unused code (we did create the factory using nearly strict TDD). Finally, we delegated from the original method to the strategy returned from the factory. Safe again, since we had tested the factory.
So far, so good. But next, we wanted to push the method down to each of the subclasses and remove the parts of the logic that did not apply to each given type. We did a spike refactoring to see what that’d be like and it was at least a little dicey. We finally decided to get the original method under test so that as we refactored, we had the safety net necessary to refactor with confidence.
We started by simply calling the method with null’s and 0 values. We worked our way through the method, adding hand-rolled test doubles until we came across our first static class.
Their current system has DAO’s with fully static interfaces. This is something that is tough to fake (well we were not using and AOP framework, so …). Anyway, this is where we introduced the instance delegator. We:- Added an instance of the class as a static member (essentially creating a singleton).
- Added a property setter and getter (making it an overridable singleton).
- We then copied the body of the static method into an instance method, which we made virtual.
- We then delegated the static method to the virtual method.
- Then, in the unit test, we set the singleton to a hand-coded test double in the setup and reset the singleton in the tear down method.
We had to do this several times and on the third time (I think it was the third time), the hand-rolled test double would have had to implement several (17ish) methods and it became clear that we were ready to use a mocking framework. They are using Moq so we started using Moq to accomplish the remainder of the mocking.
After some time, we managed to get a test that essentially sent a tracer bullet through one path of the method we wanted to get under test. When the test turned green there was much rejoicing.
However, we had to ask the question: “So what are we testing?” After some discussion, we came up with a few things:- This method currently makes calls to the service layers and those calls depend on both an enumeration (replaced with a shallow and wide hierarchy of strategies) and options (to be replaced with a composition of strategies).
- It also changes some values in an underling domain object.
So that’s what we needed to characterize.
We had a discussion on this and as a group. We wanted a way to report on the actual method calls so we could then assert (or in Moq parlance Verify). We looked at using Moq’s callbacks, but it appears that those are registered on a per-method basis. We briefly toyed with the idea of using an AOP tool to introduce tracing, but that’s for another time (I’m thinking of looking into it out of curiosity) but we decided that we could instead do the following:- Begin as we already had, get through the method with a tracer.
- Determine the paths we want to get under test.
- For each path:
- Create a test using strict mocks (which fail as soon as an unexpected method is called)
- Use a Setup to document this call as expected – this is essentially one of the assertions for the characterization test.
- Continue until we have all the Setups required to get through the test.
- Add any final assertions based on state-based checks and call VerifyAll on the Moq-based mock object.
This would be a way we could work through the method and characterize it before we start refactoring it in earnest.
This might sound like a lot of work and it certainly is no cake walk, but all of this work was done by one of the attendees and as a group they certainly have the expertise to do this work. And in reality, it did not take too long. As they practice and get some of the preliminary work finished, this will be much easier.
Overall, it was a fun week. We:- Spent time on one project practicing TDD and refactoring to patterns (they implemented 5 of the GoF patterns).
- Spent time practicing some of Fowler’s refactorings and Feather’s legacy refactorings.
- Spent a day practicing TDD using mocks for everything but the unit under test. At the end they had a test class, one production class and several interfaces.
In retrospect, the work they did in the first three days was nearly exactly what they needed to practice for the final day of effort. When we started tackling their legacy code, they had already practiced everything they used in getting the method under test.
So overall great week with a fun group of guys in Canada.