nitram509
nitram509

Reputation: 678

How to unit test a Groovy script, used in Elasticsearch for _score calculation

I want to do unit testing for a Groovy script, used in Elasticsearch.

The script itself calculates a _score, based on 3 parameters and a given formula. I want do program an automated unit test for that script, to verify its correctness.

Are there any tools available, which offer such functionality?

Upvotes: 1

Views: 1570

Answers (1)

nitram509
nitram509

Reputation: 678

I've solved the problem by mocking/emulating Elasticsearch environment in a TestNG test, using Groovy "magic".

Given the following Groovy script, which should compute a custom score value based on parameters and the documents height.

es_compute_custom_score.groovy

h = doc['height']
if (h <= 50) {
  // complex logic here ;-)
} else if (h < 1000) {
  // more complex logic here ;-)
} else {
  // even more complex logic here ;-)
}
_score = a * b + h

Then this unit test lets you walk the red/green/refactor TDD road...

es_compute_custom_scoreTest.groovy (assuming default Maven project layout)

import org.codehaus.groovy.control.CompilerConfiguration
import org.testng.annotations.BeforeMethod
import org.testng.annotations.DataProvider
import org.testng.annotations.Test

class es_compute_custom_scoreTest{

    private static final String SCRIPT_UNDER_TEST = 'src/main/groovy/es_compute_custom_score.groovy'

    private CompilerConfiguration compilerConfiguration
    private Binding binding

    @BeforeMethod
    public void setUp() throws Exception {
        compilerConfiguration = new CompilerConfiguration()
        this.compilerConfiguration.scriptBaseClass = DocumentBaseClassMock.class.name
        binding = new Binding()
    }

    @DataProvider
    public Object[][] createTestData() {
        List<Object[]> refdata = new ArrayList<>()
        refdata.add([100, 50, 5042L])
        refdata.add([200, 50, 10042L])
        refdata.add([300, 50, 15042L])
        return refdata
    }

    @Test(dataProvider = 'createTestData')
    void 'calculate a custom document score, based on parameters a and b, and documents height'(Integer a, Integer b, Long expected_score) {
        // given
        binding.setVariable("a", a)
        binding.setVariable("b", b)
        binding.setVariable("doc", new MockDocument(42))

        // when
        evaluateScriptUnderTest(this.binding)

        // then
        long score = (long) this.binding.getVariable("_score")
        assert score == expected_score
    }

    private void evaluateScriptUnderTest(Binding binding) {
        GroovyShell gs = new GroovyShell(binding, compilerConfiguration)
        gs.evaluate(new File(SCRIPT_UNDER_TEST));
    }
}

class MockDocument {
    long height;

    MockDocument(long height) {
        this.height = height
    }
}

Upvotes: 2

Related Questions