Advanced Mocking 1

Posted by wsargent Sun, 16 Mar 2008 00:10:00 GMT

I know enough about EasyMock now to feel very comfortable with it. I’ve even got an acronym for writing unit tests with EasyMock – SEREVA.

This breaks down to the following stages:

Setup the object under test with any required mocks.
Expect some methods on the mock to be called.
Replay the mock once all the expectations have been made.
Execute the object’s method when under test.
Verify the mock has had all its expectations met.
Assert the output of the method.

This basic framework takes care of most of the grunt unit tests.

But there’s more to mocking than that. There’s one particular gotcha I know about with EasyMock, and then there’s the horrible, nasty, no-good edge cases that you run into. Let’s start off.

Custom Argument Matching with Multiple Parameters

Let’s start off with the gotcha first. Say you’ve got a method like the following:

List findCarsByYearAndColor(Integer year, String color);

Say that you want to match year, but not color. You can’t say:

expect(carService.findCarsByYearAndColor(year, anyObject()).andReturn(null);

If you want to apply a custom argument matcher to either argument, you must apply it to both. So instead, you need to do this:

expect(carService.findCarsByYearAndColor(same(year), anyObject()).andReturn(null);

This is why same() exists.

Static and Final Methods

EasyMock does not allow you to mock static or final methods. EasyMock ClassExtension does not allow you to mock private methods or static classes. You can argue that such things should not exist, but we live an imperfect world where people don’t always think of our needs.

This means that dealing with final classes like java.net.URL or java.io.File are fiddly. But not impossible. There’s more than one way to skin this particular cat.

The by hand way is to use reflection: “final” is not final anymore. Heinz demonstrates how you can change final fields through several different versions of the JVM. This is a somewhat disturbing read, as it plays merry hell with my conception of what should and shouldn’t be possible in Java. But it’s there if you need it.

The snazzy way is to use JMockit, which is a small toolkit specifically designed to subvert the JVM. jMockit depends on the java.lang.instrument library, which is only available in JDK 1.5, but it provides functionality you can’t find anywhere else.

The alternative method is to say “if your code is hard to test, then your code is badly written.” While there may be a correlation, I think that what is ‘badly written code’ can only really be accurately be judged by a human being.

Private, Default or Protected Methods

jMockit is all over this.

Native methods

Don’t know.

Static or Final Classes

This is handled as above by reflection, or by jMockit.

Inner Classes

Don’t know. I suspect that anonymous inner classes are very tough. I believe that static inner classes should be accessible through jMockit, but haven’t checked.

Constructors

EasyMock 2.3 allows you to define a partial mock that will call a specified constructor. That’s good if you have something that needs to be passed into the object under test. So you can do:

public static abstract class A {
    public String s;

    protected A(String s) {
        this.s = s;
    }

    protected abstract int someMethod();
}

public void testFoo()
{
    Constructor cstr = A.class.getDeclaredConstructor(String.class);
    ConstructorArgs constructorArgs = new ConstructorArgs(cstr, "test");
    A a = createMock(A.class, constructorArgs, new Method[0]);
      
    foo.setA(a);
    expect(a.someMethod()).andReturn(0);
    replay(a);
    foo.execute();
}

If the object under testing needs to have a constructor mocked out, i.e.

public class Foo
{
    public Foo() { new File("c:\\boot.ini").delete() }

    public void methodToTest() { }
}

Then jMockit will replace non-default constructors. I don’t know of anything that will replace a default constructor.

Enums

As far as I can tell, there is no facility in EasyMock, EasyMock ClassExtension to mock out enum logic, as it is defined as final by the JVM. jMockit should be used here. And that’s it. jMockit looks like it’s branched out into integration tests as well, notably Hibernate. I know that Unitils is a competitor here, but haven’t played with either of them that much.

Toodledo 3

Posted by wsargent Mon, 11 Feb 2008 06:40:00 GMT

I’ve stopped using Ecco Pro and Shadowplan, and I’m now using Toodledo.

I looked some other online systems, but Toodledo was the only one that had both state (well, folders) AND context. Since Toodledo is a web based task system was that I’d be unable to add to it when I wasn’t in front of a computer. However, with the integrations to Twitter and Jott, I can SMS or even phone up and leave messages.

Once I found out there was an API as well, it was really only a matter of time before I’d find myself writing an adapter for it. And a command line client, in case you want to access it from a shell.

So here’s my first Ruby gem.

http://toodledo.rubyforge.org

If you’re on a mac, you should be able to type ‘sudo gem install toodledo’ and then ‘toodledo setup’ and that should walk you through most of it.

Mocking ActiveRecord Associations 4

Posted by wsargent Sat, 10 Nov 2007 05:29:00 GMT

Flexmock does mocking of ActiveRecord objects if you ask it nicely, but it doesn’t say much about associations.

It turns out that ActiveRecord does the same thing that Hibernate does and uses an internal proxy. So if you want a post containing a single image as an association, do this:

# Create a single image.
image = flexmock(:model, Image) { |mock|
  mock.should_receive(:url).and_return('/post/10/blah.jpg')
  mock.should_receive(:name).and_return('Blah Description')      
}

# It's an association proxy pretending to be an array.
images = flexmock(ActiveRecord::Associations::HasManyAssociation) { |mock|
  mock.should_receive(:find_by_name).and_return(image)
}

# The post itself.
post = flexmock(:model, Post) { |mock|
  mock.should_receive(:object_id).and_return('10')
  mock.should_receive(:images).and_return(images)
}

This is a Law of Demeter violation, so the better solution may be to have a get_images method.

More info here:

Misunderstanding the Law of Demeter Demeter’s Revenger Loose Coupling takes Tight Logic

Rails Unit Test Confusion 1

Posted by wsargent Sat, 10 Nov 2007 02:28:00 GMT

I think I understand why the unit tests in Rails were confusing me. I had assuming that unit test fixtures ran YAML into some kind of in-memory activerecord object. But in reality, fixtures will put data into a test database and then unit tests will interact with it.

As far as I understand it:

1) An integration test is one where the test code goes outside the realm of the class and has a dependency on an external entity.
2) Databases are external entities.
3) Fixtures will write to the test database.

Therefore:

Any test containing a fixture is an integration test, even if it’s in test/unit and extends Test::Unit::TestCase.

Furthermore:

Unit tests are tests that can be run in isolation, in any order, without any external dependencies.

Whew. Had to get that out of my system.

Not that I don’t understand the rationale; or that using fixtures could be extremely handy. But a spade is a spade.

As usual, as soon as I realized the underlying issue, there was no shortage of help, Jay Fields being the most helpful.

Starting from Scratch

Posted by wsargent Mon, 05 Nov 2007 06:35:00 GMT

A little over a week ago, I made the appropriate sacrifices, made a backup to an external machine, setup a new computer (after figuring out why it wouldn’t POST with a USB keyboard plugged into it) and then transferred the hard drives of my old computer into the new one.

Long story short, the hard drive with all my important data died, and the backup contains some hairball that causes the backup server to freeze when the data is transferred. Oh, and my laptop died as well. The same day.

Ever get the feeling the ground has just crumbled under your feet?

I lost some stuff. Most annoyingly, I lost all my software registration keys. This is good in a way – it means I can try mint.com without having to worry about my old data. And I’ve found that I tend to use online services such as Google Docs and Google Bookmarks over any local solution, so in some cases there is no need to backup at all.

I spent most of the beginning of the week reinstalling my toolkit: Perl, Java, Ruby, RSIGuard, jEdit, etc. And making sure this can never happen again. I have everything local (and this server) backed up onto Amazon S3, using s3sync. I also have a weekly backup of the database onto S3, and I’ve already restored it to check it’s still good.

Of course, it’s going to take me three full days to upload my MP3s onto S3, but I think it’s going to be worth it. And eventually, iTunes will get smart enough that I’ll never need to download them again.

TMI

Posted by wsargent Fri, 26 Oct 2007 04:29:00 GMT

A problem I have learning Ruby on Rails is that there is such an active community base that I can’t simply pick up what I need to know without getting sucked in.

For example. I want more integration tests. So I need fixtures to plop data into the test database. Fixtures are written in YAML.

Well, all my data’s in the development database. I suppose I can hunt through Google. Ah. I can export it to YAML.

And there’s a plugin that will allow YAML to be created with fewer foreign keys. Okay. I can use that then.

And the fixtures aren’t run in dependent order. Okay.

Oh, there’s another way to do do that. Okay. I’ll use that instead.

And Rails doesn’t tear down fixture data. Okay…

By the time I’ve read through everything in Google, I’ve forgotten what the heck I was trying to do in the first place. It doesn’t help that some of the blog posts date back to the point where it’s part of the core Rails package now – I have no ability to distinguish between old and new.

So. Start at the beginning again. I want more integration tests. Step 1: Ignore Google.

Rewrote the blog in Ruby on Rails 3

Posted by wsargent Thu, 25 Oct 2007 06:21:00 GMT

Rewrote the blog in Ruby on Rails. Thanks, Aaron. Comments are now back online, after I had to shut them off due to comment spam. The blog now runs all comments through Akismet.

I don’t really have much to say about Ruby or Rails that hasn’t been said by many people before; I just have my experience of it, which I think is more valuable than the technical minutiae.

I think the biggest strength of Rails (and Ruby for that matter) isn’t the framework. It’s the community.

The framework solves the problem it’s supposed to solve. The community is all aligned around an agile mindset. As such, there’s not the “There’s more than one way to do it” philosophy of Perl. Instead, the philosophy is “How do we make this simple, flexible and easy to build on?” When you’re working along the same assumptions, Rails makes it very, very easy to do what you want. The community supports that, not just with tutorials, but with podcasts, screencasts, and books.

However, if you’re doing something that isn’t in that set of assumptions – if you have legacy data or non-Railsy database schema and associations – you’re off the map. In a way, this was good because I got to figure out how Rails really works, but it was certainly a dunk in cold water after having so much help available.

This has been something I’ve wanted to do for years. Gave up some features for it; no automatic java syntax highlighting, no full text search, and no filtering by categories. But I’ve got the bones, and I can work on the flesh later. Now, sleep.

Hardcore Zen 1

Posted by wsargent Mon, 01 Oct 2007 05:00:00 GMT

A year and a half ago, I read Hardcore Zen.

I had some understanding of Zen (or so I thought) from reading Hofstader and Pirsig, a short reading through Watts. To me, Zen was about the destruction of ideas; an deconstructionist, almost dada-ist religion where thoughts were meaningless, desire was shunned and even the religion itself “could only be learned by forgetting it.” I’d hear stories of people going weeks without speaking in a retreat, trying to answer unanswerable questions, staring into a candle-flame, and trying to eliminate their very idea of self. Didn’t sound very fun, or practical, or even useful.

I’m not religious. I barely care enough to be an atheist. So why was I reading the book?

Mostly because of the cover. “Question authority. Question society. Question reality. Question yourself.” And then, in a smaller font: “This is Zen for people who don’t give a rat’s ass about Zen.”

Or maybe it was the inside quote: “I have no time for lies or fantasy and neither should you. Enjoy or die.” – Johnny Rotten.

Whoever this guy was, he was not a hippie. And when I started to read, the author took the attitude I had and neatly reversed it; embracing sceptical thinking, pointing out the holes in his experience and his distinct lack of Zen Master enlightenment. And his refreshingly blunt, clear opinions on organized religion, including Zen masters and koans. I liked him. Whoever he was, he thought like I did. I’ve never liked being given a pat answer or being told “Don’t look too deep. Don’t ask too many hard questions. Don’t ask why.”

So that’s why I read Hardcore Zen. And the interesting thing about having read Hardcore Zen is that it didn’t tell me anything I didn’t already know. I’ve had people return it, saying that it just says what’s obvious anyway. And that’s why I like it so much. Zen, at least in some minds, is not about transcendence or enlightenment, or nirvana. It’s about pointing out what’s in front of you, again and again. Not to take it for granted. Not to assume it. Zen isn’t about staring off into the distance. Zen is about paying attention.

As a consequence, Zen has many things to say about how the brain works. Cognitive Science can tell you how we reshape the memories of the past to fit how we see the present. How we then dream about the future instead of seeing the present as it is. That how we see ourselves acting in theory is not actually how we act in practice. Zen has been saying this for thousands of years.

Zen holds a light up to how inconsistent human beings are, and how little we understand about ourselves. And Warner goes into detail about how this applies in practice, to him in particular. A good portion of the book details just how much damage “paying attention” can do to your carefully groomed ego. Warner starts off playing in a punk band, and realizes how much punks depend on authority (police) to allow them to rebel against it. He sees punk turn from being a way to express individuality to a set conformity with its own dress code. He talks about people who spend day after day trying to solve all the world’s ills… but then come home and treat themselves and their friends like crap. And even as Warner tries to dismantle the concept of authority, he has to struggle with the possibility of being an authority figure in his own right; a punk rock guitarist turned Zen Master.

But more than that, Warner realizes just how much of an asshole he can be. He has to face up to everything he’s done, and everything he’s still doing. He starts to see his emotions and desires more clearly, and they’re not always fun to see. He quotes his brother-in-law as saying “It’s impossible not to feel angry when you are facing the gale-force winds of your emotions whipping across your body.” But he says another idea of anger is “sitting in the bathtub frantically thrashing around and throwing handfuls of water into the air while simultaneously wondering why the hell your head and face keep getting wet.” Being angry is intoxicating, but who and what is causing this anger? It’s not coming from the situation. It’s the reaction to the situation that is anger. It’s coming from inside.

And finally, he talks about life as it is. That reality is ultimately waking up in the morning, pulling your sorry ass out of bed, and trying to figure out which limbs do what when you’re brushing your teeth and getting dressed for work. That enlightenment is as much about being okay with being stuck in traffic as it is about seeing the face of God.

Hardcore Zen doesn’t tell you anything you don’t already know. But to me, at least, it reminds me that I know it. And maybe, just maybe, with sustained effort and careful attention, I can be less of an asshole.

The Problem with Advice

Posted by wsargent Thu, 27 Sep 2007 07:21:00 GMT

The novice comes in to the monastery and says “I really want to be a monk. What is it you do at one of your sesshins?”
The monk thinks about it and says “I sit on a cushion and I stare at a wall. Oh, and I breathe.”
The novice says “Okay, I’ll do that. How do I do that, exactly?”
The monk gets him a cushion to sit on, and tells him “Now breathe.”
The kettle whistles and the monk leaves the room to take it off the heat.
The monk comes back in a minute later, and looks at the novice.
The novice looks frantic. The monk sighs.
“Breathe out. Once you’ve finished breathing out, breathe in again. Keep doing that.”

Biking Lessons 1

Posted by wsargent Mon, 24 Sep 2007 17:06:00 GMT

Today I learnt that human beings cannot fly. At least, not for very long.

Also, Sports Basement does not sell Neosporin.