1

I have written some code in Katalon Studio (known as "custom keywords") whose job is to map the rows of a Data File, to models for testing. (Say goodbye to hardcoded column indices and findTestData("YourDataStoreName") all over test case code!)

It is defined to be:

package com.xxx.builders

import java.util.stream.Collectors

import com.kms.katalon.core.testdata.TestData

public abstract class BaseModelBuilder<T> {
    protected TestData testData;

    public BaseModelBuilder(TestData testData) {
    this.testData = testData;
    }

    public List<T> createModels() {
    return this.testData.getAllData()
        .stream()
        .filter { row -> row.stream().anyMatch { String cell -> cell != null && !cell.isEmpty()
            } }
        .map { row -> this.createModelFromRow(row) }
        .collect(Collectors.toList())
    }

    public T createModelFromRowNum(int rowNum) {
    return this.createModelFromRow(this.testData.getAllData().get(rowNum))
    }

    public abstract T createModelFromRow(List<Object> row)
}

and when we want to use it, we extend it, for example :

package com.xxx.builders

import static com.kms.katalon.core.testdata.TestDataFactory.findTestData

import com.xxx.constants.Formats
import com.xxx.enums.Frequency
import com.xxx.enums.Signatory
import com.xxx.models.contract.ContractModel
import com.xxx.models.contract.details.BankDetailModel

public class ContractBuilder extends BaseModelBuilder<ContractModel> {

    public ContractBuilder() {
    super(findTestData('PracticeContractData'))
    }

    public ContractModel createModelFromContractID(int contractID) {
    int contractIdx = this.findContractIndex(contractID)

    return this.createModelFromRowNum(contractIdx)
    }

    private int findContractIndex(int contractForeignKey) {
    for (int $j = 1; $j <= this.testData.getRowNumbers(); $j++) {
        if (Integer.parseInt(this.testData.getValue(1, $j)) == contractForeignKey) {
        return $j
        }
    }

    return -1
    }

    @Override
    public ContractModel createModelFromRow(List<Object> row) {
    return new ContractModel(
        Integer.parseInt(row[0]),
        Formats.DateFormat.parse(row[2]),
        Formats.DateFormat.parse(row[3]),
        Integer.parseInt(row[4]),
        row[6],
        Double.parseDouble(row[5]),
        Frequency.valueOfText(row[7]),
        Integer.parseInt(row[8]),
        Integer.parseInt(row[10]),
        (row[11] == 'Y'),
        Integer.parseInt(row[12]),
        row[13],
        Signatory.valueOfText(row[14]),
        new BankDetailModel(Double.valueOf(row[15]), Double.valueOf(row[16]), Double.valueOf(row[17])),
        Double.valueOf(row[18]),
        )
    }
}

, and then call it, typically in enhanced for-loop, like for (YourModel model : new YourBuilder().createModels()) { /* test code */}

The problem is that I don't know what to call this solution. I'm probably wrong about this, but...It doesn't seem to fit neatly into factory design pattern, and doesn't have the static inner-class status and field-matching that a proper builder does...

What is the correct name for this design pattern?!

DISCLAIMER: Katalon Studio's runtime environment is in Groovylang, which is a dialect of Java.

5

... It doesn't seem to fit neatly into factory design pattern, and doesn't have the static inner-class and field-matching that a proper builder does ...

I've written dozens, possibly hundreds of builders over the years. None would have had a static inner class as I really don't see the need for one. They were still proper builders as they followed the builder pattern of supporting repeated adding of data until complete and then calling Create, Build, ToList or whatever to build the final data set.

Patterns are design patterns, not implementation patterns. As such, how they are implemented should be determined solely by the need of your code. Do not mistake the UML diagrams that litter pattern books, Wikipedia etc as somehow being the one correct way of using that pattern. They are not. They are merely one possible way of implementing each pattern.

Your solution is an example of the builder pattern.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.