Introduction

One of the many straplines of ScriptRunner is

making easy things easy and hard things possible

another one is

letting unqualified people do hacky stuff

Although you don’t go through all the maven pain, you can do anything in a script that you could do in a plugin. But because you maybe haven’t been on that journey, there are perhaps some aspects of development that weren’t inculcated in you, such as the need for automated testing. Automated testing will give you peace of mind because you’ll ensure that your script does what you want it to, including when there were corner cases that you might not anticipate.

The other advantage is you will feel more confident when you upgrade JIRA, that the APIs still function as they did before.

These are integration tests - they test your code within the context of a running JIRA. A unit test by contrast would focus on testing only your code - this requires isolating your code by mocking any JIRA managers and services. In the context of scripting, I find these kinds of tests have little value as a) scripts are generally comparitively simple and b) mocking everything is prohibitively expensive. Integration tests work well - if you upgrade then your script starts failing with a compilation error you can be confident it’s because an API has changed.

Test Runner

The way we have been working on built-in scripts is through the Test Runner within the plugin.

image2014 10 1%2021%3A44%3A11

When you first see the test runner the package will be set to com.acme.scriptrunner.test, which contains some sample tests shipped with the plugin (read the walkthroughs on testing workflow functions and script fields for explanations). You should be able to run all of the tests (one is supposed to fail to demonstrate what a failing test looks like).

Avoid running tests on a production server

Running the tests will create a project with key SRTESTPRJ, and a workflow and workflow scheme. All these are safe to delete and will be recreated each time you run the test.

When you write your own tests you will want to change the default package. If you want to use the included tests as a basis for your own, you can extract them from the plugin with winzip or whatever.

When starting on a new feature, the way I work is generally to write a test for what I want to happen. Run the test, it fails (at least it should). Implement feature until test passes, refactor, make sure tests pass etc. Writing tests is the same as any other script - just save the file and click the Run button in JIRA. No compilation or plugin upload etc.

Two test libraries are included, Spock and JUnit. I recommend you use Spock.

When running the test runner you will need to specify the base package(s) that you wish to keep your tests under, generally something like com.yourcompany.jira.test. In this case you would have a directory com/yourcompany/jira/test under your script root, where you will keep test classes. Make sure you are using a source control system, so that you can test on your dev instance, commit your changes, then update your working copy on your production system.

The tests should create whatever JIRA data structures that are required. Although it’s tempting to create workflows and fields in JIRA, ideally it’s best if you don’t, so that the tests are portable between instances without having to do a load of manual setup.

For instance, if testing a workflow function you will want to create a workflow, a workflow scheme, a project, and finally an issue, and then drive it through the workflow. This sounds complex, and it is in fact, but I have shipped some base classes that you can extend that will do most of this for you.

Typically a test will create these structures and remove them after completion, leaving the system in the same state as before the test. However, in the case of the support classes they will remove them if already present at the start of each test suite, and leave them present afterwards. This is to give you a chance to manually inspect the workflows etc to make sure you created them as you wanted to.

Depending on what you want to test you will start with a different base class. Let’s start with the hardest of these, testing workflow functions, by going through an example.

Although you don’t need the supporting classes, they may make life easier, as they will create a test project, and either a test workflow and scheme, or a script field. Depending on what you’re testing, extend one of the following classes:

Testing what

Class

Walkthrough

Workflow Functions

com.onresolve.scriptrunner.test.AbstractWorkflowSpecification

Testing Workflow Functions

Script Fields

com.onresolve.scriptrunner.test.AbstractScriptFieldSpecification

Testing Script Fields

It may well take you half an hour to write the tests, when you’re up to speed, even if it only took 5 mins to write the script. Still, it’s worth the investment in my opinion.

Running Tests from your IDE

You can run tests from your IDE (we have only tested with Intellij IDEA).

The way this works is that a test runner executes them via REST, in the running application (JIRA, Confluence, Bitbucket etc). In order for the IDE to know which runner to use you must annotate your test class using the @RunWith annotation. Example:

import com.onresolve.scriptrunner.canned.common.admin.ScriptRunnerTestRunner
import org.junit.runner.RunWith
import spock.lang.Specification

@RunWith(ScriptRunnerTestRunner)
class TestRunnerSampleSpec extends Specification {

    def "test something"() {
        expect:
        true
    }
}
When you add a new test class, you must build your project (mvn package). This is because the tests are invoked locally, and unless the compiled class is available the IDE cannot know which test runner to use. After this initial build you can add new test methods and execute them without rebuilding.

IDEA Configuration

The IDE runs your test locally, which executes a REST call to the app. Therefore the IDE needs to know the address of your running application, so it can tell the app to run the tests. To do this you can modify the default setting for Junit tests:

Do Run → Edit Configurations, then open Defaults → Junit, as shown below:

debug test config
  1. Add a property -Dbaseurl= pointing to the url of the running application. You can omit this if you are using http://localhost:8080/jira

  2. Under Before Launch, delete the Build task using the "minus" button. It’s not necessary to rebuild the plugin after editing the tests, as ScriptRunner will recompile the test if necessary

  3. Uncheck the "Activate Tool Window" box. It’s not useful to switch to the tool window, as any failures will be shown in the main "log" window

As mentioned, any exception will be shown in the tool window, but log messages are not redirected to it, so in practice there is little point in looking at the tool window.

You can run the code by clicking the annotations in the margin, as shown below:

debug test code

Or better still, put the cursor in the test class name or method name, and press Ctrl + Shift + F10.