admin

Aug 182005

I’m sure this can’t be original – most of it has come about from talking to my colleagues, or is nicked from the way JBehave works and my attempts to use it – but I wanted to write it down so that I’ll remember next time. It’s a bit long and techy. Forgive me.

JBehave introduced me to the idea:

  • Given a context
  • When these events happen
  • Expect this outcome to occur.

At the moment, our team writes the context by performing the steps which get us into that context – we run a scenario, which might be the first part of an existing story test. It might be the first part of tests for a lot of stories. This means that we’re duplicating bits of tests. It often means that the same code appears twice in different tests. It certainly takes time to run.

Here are some stories:

  • As a sheep farmer and organic wool producer, I want to shear sheep and sell the raw wool so that I can make money.
  • As a sheep farmer and organic jumper maker, I want to shear sheep, spin the wool, make jumpers and sell them so that I can make money.
  • As a sheep farmer, I want to shear sheep and record the weight of wool sheared so that I can breed the best wool producers.
  • As a sheep farmer, I want to shear sheep and record the date on which they were sheared so that I know when to shear them again.

All of them require the shearing of a sheep. I imagine nice little screen in which you can add the details of your sheep to the database, then pick which of your sheep were sheared, what weight of wool was produced, etc. Filling in these screens for every story doesn’t give you any value in terms of code confidence the second time it’s done. Why not just do it once, then pretend that it’s been done for every other story?

So here’s my idea for cleaner, quicker acceptance testing.

Context

We write the first part of an acceptance test. The bit of the test which gets us to this point of the story is a class of its own, and implements a contextual interface. So, for instance, we might test that when we shear a sheep, weigh the wool and tell the app that we’ve put it in the cupboard, we get records that there are 3kg of wool in the cupboard. We could also, if we wanted to, check that one of our sheep was shorn on the 13th August 2005. We would name this test SheepShearingTest, and it might implement the interfaces ThreeKilogramsOfWoolAreInCupboard and BlackieIsShorn, both of which would extend the role of Context. (In JBehave there’s a Context interface). If we want to make these contexts reusable, we can always just call them RawWoolInCupboard and SheepIsShorn and either set parameters which configure them or respond to the configuration in our tests.

At this point in the acceptance test, we can check the state of the domain model – eg: check that we have 3kg of wool in our class representation of the domain. This isn’t part of the story test itself. It might even have a class of its own – RawWoolInCupboardVerifier. This verifier takes a domain model in its constructor, possibly through interfaces only, and has methods to allow you to check the bits you’re interested in. It might even be able to check what shades or species of wool are in the cupboard, what date they were put in there, etc. It’s reusable, so you can put it into lots of tests. It should also be pretty quick to run. Each test should only use the verifications it’s actually interested in.

Event

The second part of our acceptance test deals with the events which happen – eg: spin the wool. This, we just ‘do’. Whatever we use to do it implements interfaces – for instance, WoolSpinner. The implementing class is part of the production code. If we don’t have code to do this, we can write it as we complete the story, unit testing as appropriate.

Outcome

Running the events on the context gives us an outcome – 10 balls of wool in the spun wool cupboard. We write another checker for this. It might also be in its own class, which implements an interface of its own – SpunWoolInCupboardVerifier. You get the idea. (In JBehave, we also have an Outcome interface).

Now, when we construct our test, we can dependency-inject it with the contexts, the bits of code which actually do the events, and the outcome.

And they’re all reusable. They’re all clean. Best of all, they encourage us to think about the domain model; to write our application code cleanly, around that model; to understand the points at which events converge, and package the application classes appropriately.

Things I really like about this approach

  • At any point, you can replace the context of an acceptance test with anything else that matches the context / outcome Verifier – a stub of a domain model, a domain backed by a test database, or a slightly different method of getting into the same state.
  • The outcome of one event can be used as the context for another.
  • You can even do the same thing with the events.
  • The stubs or mocks for a context can be written before the real code to get to that point has been developed – so any part of a system can be produced to an interface without waiting for other parts. The Verifiers help check that the real system does actually produce the expected result. Top-down or bottom-up – doesn’t matter.
  • If we have a bug which requires a bit of deviation from the simple story, we can use the same context and outcome classes as the simple story tests do, and just change the events. And as long as we can create the same context without running the application, it doesn’t matter whether we use the real application, or just build up an appropriate domain model as if we really had used the application.
  • The Verifiers themselves can be implementations of interfaces – for example, one might just check the domain model; another might check that the database has changed. Which checker you use would depend on whether you’re running real code, or just stubbing the model out, or mocking a system… etc.

JBehave is not yet at version 1.0 – it needs a bit of work. The unit behaviour classes are good, but the story runner isn’t done yet. It promises to be good, and to support the framework above. I can’t wait till it’s finished, so I’ll be putting some more effort into it next week.

Jun 142005

Reading Esther Derby’s article on peer to peer feedback made me remember something that happened a few years ago (not here, I hasten to add). I’m sharing this as an example of how peer to peer feedback can resolve a situation, so that any women out there who are experiencing something similar might take courage and do something about it, and because maybe it might give any men out there who indulge in this kind of behaviour an idea of what it’s like to be on the other side. This, gentlemen, is why the sexual harassment and discrimination laws were invented, and why so many women end up in court and the front page of the Times.

The company had a fairly laddish, alcohol-fuelled culture with only a few women (about 10%). The lines of ‘appropriate behaviour’ were somewhat blurred. If you’re female, have attractive qualities, and want to know what it’s like to work in a company with this kind of culture, go down to your local next time England are playing on a Saturday afternoon and take a seat. Hang around after the game. Most of the attention will be on the football, just as most of the company got on with their work, but there will be the occasional innuendo or flirtatious comment that may not be entirely unwelcome. Plenty of women thrive on attention. I certainly enjoyed my time with the company, and was sorry to leave the many friends I had made there.

However, sometimes blurred lines get crossed. This is the story of one such incident.

We had a secure project in the basement with no network access. An office upstairs had been set aside as a “daylight room”; a place where people could come to check their mail, browse the web and stare out of the window. I was off-project, and had been assigned a spare computer there to get on with training. So there I was, trying to concentrate, while across the way my colleagues were trying to guess the cup sizes of various women whose unclad attributes were displayed across the 19 inch monitor.

Now, I’m not easily shocked, and I could probably have ignored it, or just asked, “Honestly – do you have nothing better to do with your time?” But there was another aspect to this that stopped me from saying anything – something which made me sit as quietly as I could, blushing to the roots of my hair, and trying to bury myself in my work. The three gentlemen who were standing up behind the one colleague I knew were staring across at me, whispering amongst themselves, gesturing and giggling like schoolboys; applying their imaginations in the spirit of the competition to the only real-life example in the room.

I had three options. I could have stayed quiet and ignored it, and hoped it didn’t happen again, or maybe gone out and made a cup of tea till they moved on. I could have taken my problem to the senior management, or to the MD, both of whom were quite laddish themselves but understood the lines better than the younger company staff. The option I chose was the most difficult, and I only did it because – well, did you read my apprenticeship story? The rather scathing review that I got in my earlier years regarding the quality of my code? No one gave that review to me to my face, and finding out six months later hurt. Like a physical blow. It said more about people’s ability to talk to me, or their care for my work and professional well-being, than it did about my code. This was only a month or so after the review, and it was very fresh in my mind. So I took the third option, and caught the one colleague I knew (let’s call him Ted; not his real name) as he was leaving the room.

“Ted, can you spare a couple of minutes?”

“Sure. What’s up?”

“It’s the material you were looking at over lunch. I’d prefer it if you didn’t do that again. It’s distracting, and it made me feel very uncomfortable.”

“Oh. Um, okay. I didn’t think you’d mind; you’re pretty open-minded about that kind of thing. I’ve never seen it bother you before; we were just having a laugh.”

“Ted, do you know what your friends were doing while you were browsing the site?”

He didn’t. I told him. Blushing furiously.

“Oh. God, Liz, I’m so sorry. You must have been really embarassed. I had no idea…”

“No, I could tell. Ted, you need to know that this was hard for me. I nearly went to the MD instead of talking to you, because I feel embarassed just confronting you about this. Maybe there are other women in this company who’d do that. You shouldn’t make assumptions about how people will react to that kind of content, or how it will make them feel.”

“Liz, thank you. I’m glad that you told me; I can tell that it was difficult for you, but I really appreciate it. I’ll talk to the others and make sure it doesn’t happen again.”

We got on just fine after that.

I can’t actually imagine a more difficult and embarassing situation to be in than that one (except those incidents at office parties that are problems entirely of our own making!), but in retrospect I’m really glad I dealt with it this way. It’s given me the confidence to take people aside when I need to. I try not to let third parties deliver my messages any more. Because of this new confidence, I was able to help a developer I was mentoring become aware of his mistakes and improve his coding techniques well before his review. I was able to tell a colleague that smoking cigars is not better for you than cigarettes, and they smell far worse. I was able to tell the team leader who gave me the poor review about my frustration with getting the feedback on my code so late. Before I left, I also had a frank, open-minded and constructive discussion with a senior manager regarding the company culture and the problems it presented to female staff. And I told him this story as I’ve just told it to you.