Having succeeded in getting a simple JBehave story running. my next challenge is to scale it up a bit. In particular, I want to get a JBehave story that integrates with Spring to do something more fully-featured: save an entry in a database.
Because I don’t yet trust JBehave enough to let it drive my application, I’ll back up this with a conventional JUnit test – that will let me know that the story is doing what its meant to do.
To start with, I copied the Simple JBehave scenario from last time, just to get things moving. I then created a simple database app, using a gist I’d prepared a while ago as a template. At this point, the app doesn’t do anything – it’s just a single persistent class.
@Entity @Table public class Foo { @Id @GeneratedValue(strategy = AUTO) private long id; @Column(length = 50, nullable = false, unique = true) private String name; @Column(length = 200, nullable = true) private String description; Foo() { // for hibernate. } public Foo(String name) { this.name = name; } public long getId() { return id; } public String getName() { return name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } }
I want to augment this with a simple service that I’ll write the JBehave story for. So the next step is to create the service.
@Repository public class FooService { @Autowired private SessionFactory sessionFactory; @Transactional public void createFoo(String name, String description) { Foo foo = new Foo(name); foo.setDescription(description); sessionFactory.getCurrentSession().save(foo); } }
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("/testContext.xml") public class FooServiceTest { @Autowired private FooService test; @Autowired private JdbcTemplate jdbc; @After public void cleanData() { jdbc.execute("truncate schema PUBLIC and commit"); } @Test public void test() { assertEquals("we start with no foo", 0, jdbc.queryForInt("select count(*) from foo")); test.createFoo("foo", "this is a test foo"); assertEquals("we end with one foo", 1, jdbc.queryForInt("select count(*) from foo")); Map results = jdbc.queryForMap("select * from foo"); assertEquals("foo", results.get("name")); assertEquals("this is a test foo", results.get("description")); } }
Again, this is a really simple test, but it’s a good starting point. I need to make sure that the JBehave test that I write can cover this as well.
(A key thing to note here: the FooServiceTest
is not transactional, and doesn’t automatically rollback. This is intentional – it means that I’m testing the transactional semantics of the code. This still counts as a unit test, though, because it’s an in-memory database – deleting all the data is no slower than rolling back the transaction. The JBehave test will need to be able to do the same thing)
Now that we have a working service, it’s time to move on to the JBehave work. Let’s start with the story.
When we create a Foo called 'bar' Then it gets saved in the database with the name 'bar'
And the Story and Steps:
</pre> @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("/testContext.xml") public class FooServiceStory extends JUnitStory { @Autowired private ApplicationContext context; @Autowired private JdbcTemplate jdbc; @After public void cleanData() { jdbc.execute("truncate schema PUBLIC and commit"); } @Override public Configuration configuration() { return new MostUsefulConfiguration(); } @Override public List<CandidateSteps> candidateSteps() { return new SpringStepsFactory(configuration(), context).createCandidateSteps(); } }
@Component public class FooServiceSteps { @Autowired private FooService test; @Autowired private JdbcTemplate jdbc; @When("we create a Foo called 'bar'") public void createFoo() { test.createFoo("foo", "this is a test foo"); } @Then("it gets saved in the database with the name 'bar'") public void lookForFoo() { assertEquals("we end with one foo", 1, jdbc.queryForInt("select count(*) from foo")); } }
Again, this is kind of brain-dead simple, but it works. The feedback from running the test inside the IDE is pretty poor, but I can make the test pass or fail by changing the assertion. So, at this point, I’ve got a Spring-enabled JBehave test.
One part that should be explained is the candidateSteps()
method. This is the method used by the JUnitStory
super-class to find the step classes. The SpringStepsFactory
is a JBehave class that knows how to use a Spring ApplicationContent
– it looks through all the beans defined in the context to see if they have JBehave annotations on them.
That’s where I’m leaving it for now. In the next instalment, I want to make this be based off JBehave’s own infrastructure for Spring, as opposed to leveraging the JUnit stuff. It’s my sincere hope that going that way I can improve the in-IDE experience, as well as improve the reporting. I’m a long way from being happy with this right now.
Update: I’ve updated the example to use the SpringStepsFactory
class to create the step. This is a better approach – especially if the test shown above was a base class, or if it extended from the JUnitStories
class instead.
You should look at the JBehave example on Spring Security – shows how to test Spring-based services (in this case Spring Security AuthenticationManager authenticate method) with JBehave.
Thanks, Brian. My research is running ahead of my blog posts – I have looked at those, and my one of my next posts in this series will be using a similar technique (in particular, using the
SpringStepsFactory
demonstrated there). My next post, though, is going to look at theSpringAnnotatedEmbedderRunner
(though I may yet decide to reverse that order… 😉For those playing along at home, the examples can be found at the JBehave Github account
I’ve updated my example to use the SpringStepsFactory, as per the Spring Security example – it is a better approach, and I would probably have got there on the first draft if I didn’t post at 11pm at night. 😉