For the last two JIRA releases we have been working hard to revamp our in-browser acceptance test suite by developing a library of reusable page objects. In this three-part blog series (part one, part two), I talk about what we did and how JIRA plugin developers can make use of that work.

In this final part I will show how you can make use of our JUnit4 utilities to abstract away repetitive activities performed in your acceptance tests and thus further reduce code duplication and improve readability.

JUnit4 integration

Components

While building the page objects library we also invested a lot of time to build up the infrastructure around the new test suite. We use JUnit4 and if it is your test platform as well, you will be able reuse some of this goodness in your plugin’s tests. By extending CompositeTestRunner you can plug in pieces of infrastructure code that will run before and/or after your test to perform common set up and clean up tasks that further reduce the boilerplate. Just take a look at JiraWebTestRunner and choose components that you want to apply in your tests. You can also provide custom JUnit4 run listeners that you want to hook into your tests. Then put JUnit4’s @RunWith annotation on your tests and enjoy! The composers and listeners that might com in handy are as follows:

  • restore data – supports two annotations that you put on your test classes (@Restore, @RestoreOnce) to automatically restore data from prepared XMLs
  • clear cookies, maximize window – clean up the browser state before each test
  • LogPageSourceListener – dump page source to logs (and a file) upon test failure
  • ScreenshotListener – dump screenshot of the current page upon test failure
  • LogTestInformationListener – log information about test suite as it’s running

Smarter test set up

In particular, as your test suite grows larger, we encourage you to start using @RestoreData (you may also access it directly in your set up code, just by @Injecting RestoreJiraData into any page object) so that you start each test having JIRA populated with a well-defined data set. The usual ‘approach’ would be to create the data in your set up methods by just excerising JIRA via browser. There are two main disadvantages of this approach: it’s slow (you probably have to navigate to multiple pages to set up all the data you need) and it’s fragile: you have to either make sure that the data you created for one test will not affect other tests in unpredicted ways, or take care of manually cleaning up the created data after each test. The latter may quickly turn into non-trivial task. In our experience (keep in mind JIRA test suite is quite big and complex) it is usually a recipe for intermittent, hard-to-debug failures. That’s why we have chosen to make use of the XML restore functionality. It’s usually faster than setting up/tearing down the data manually and it allows us to stick to the fundamental principle of unit tests: start your test with a well-defined state of the world without any random factors (read: data left over by previous tests) in play.

Using JUnit4 runners might seem quite invasive and there is already an effort going on in atlassian-selenium to make wider use of JUnit4 rules for extra goodness like the above. Don’t forget that all of the above may be applied without custom runner magic, straight in the tests. For instance, to inject component for restoring data into your page objects:

public class DataRestorer {@Injectprivate RestoreJiraData restoreData;
public void doRestore(String resourcePath) {restoreData.execute(resourcePath);}

Look up the sources to check out how other bits and pieces are implemented. If you feel like contributing TestNG equivalents to the above components, you are most welcome!

It’s all over!

This is it, pretty much! We hope that this introduction will kick-start you into the new world of functional testing and writing functional tests for your JIRA plugin will be like a breeze! To get you up to speed with the idea and APIs, we will soon be releasing documentation of the core atlassian-selenium framework on our documentation hub – keep an eye on it! A short summary of other important links:

As a final note, please do not let the 4.4 mark on the atlassian-jira-pageobjects module (which is only there to say that this version is compatible with page layout of JIRA 4.4) trick you into thinking that it’s a final, supported bug-free version. In fact, there are known glaring bugs in this library. Please look at it as what it really is: an internal test library that is under constant development, as new features in JIRA are being added and tested. The beauty of the page binder solution is in that even if you do encounter a bug or a shortcoming in the existing page objects that prevents you from writing your tests, you may easily create your version of the page object (don’t hesitate to rip off the existing imperfect code as a starting point) and then just tell page binder to instantiate it. That way you can plug in your page objects and freely mix them with the existing ones. If you feel that your page objects could be valuable on a broader scale, send us your changes as a patch and you may see them in the next atlassian-jira-pageobjects milestone.

We have already started to use JIRA page objects in testing of various Atlassian plugins and hosted versions of JIRA and the benefit is immediately visible. This is just a beginning of exciting changes that should result in every Atlassian product providing its own library of page objects, free to use by anyone. We hope that JIRA page objects will contribute to faster development velocity and higher quality of your plugins!