1

I am writing template method pattern for Sorting (SelectionSort, InsertionSort and QuickSort). I wrote SelectionSort interface, following by its implementation (SelectionSortImpl) and then its unit tests with JUnit (SelectionSortImplTest).

As a next step, I refactored to extract template method. I put the only sort() method from SelectionSort interface, put it in a new interface AbstractSort, implemented its abstract class namely AbstractSortImpl.

Now, I realize that the SelectionSortImplTest contains unit tests which would be common to all implementations (SelectionSort, InsertionSort, and QuickSort). I want to refactor SelectionSortImplTest, such that it becomes AbstractSortImpl. The idea is to change only one line of code in my @BeforeEach setup from the type of sorting technique (such as from SelectionSortImpl to InsertionSortImpl).

How can I do this?

Following my code:

package algorithms.sorting;

public interface AbstractSort {
    void sort(int[] arr);
}
package algorithms.sorting;

import java.util.Arrays;

public abstract class AbstractSortImpl implements AbstractSort {
    protected int[] inputArr;

    @Override
    public final void sort(int[] arr) {
        this.inputArr = arr;
        sort();
    }

    protected abstract void sort();


    protected final void swap(int i, int j) {
        int temp = inputArr[i];
        inputArr[i] = inputArr[j];
        inputArr[j] = temp;
    }

    public static void printArray(int[] arrToPrint) {
        System.out.println(Arrays.toString(arrToPrint));
    }

}
package algorithms.sorting;

public class SelectionSortImpl extends AbstractSortImpl {

    @Override
    protected void sort() {
        int minValueIndex;

        for(int candidateIndex = 0; candidateIndex < inputArr.length - 1; candidateIndex++) {
            minValueIndex = findMinValueIndex(candidateIndex);
            swap(candidateIndex, minValueIndex);
        }
    }

    private int findMinValueIndex(int index) {
        int minValueIndex = index;

        for (int indexer = index; indexer < inputArr.length; indexer++) {
            if (inputArr[indexer] < inputArr[minValueIndex]) {
                minValueIndex = indexer;
            }
        }
        
        return minValueIndex;
    }

}
package algorithms.sorting;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.Collections;
import java.util.Random;

class SelectionSortImplTest {

    public static final int NO_OF_ENTRIES = 10;
    private int[] uut;
    private SelectionSortImpl selectionSort;

    @BeforeEach
    public void setup() {
        selectionSort = new SelectionSortImpl();
    }

    @Test
    public void sort_EMPTY() {
        uut = generateRandomArray(0);

        runTest();
    }

    @Test
    public void sort_NON_EMPTY_UNSORTED() {
        uut = generateRandomArray(NO_OF_ENTRIES);

        runTest();

    }

    private void runTest() {
        int expected, actual;

        // Test preparation
        expected = 0;
        int[] copiedUut = new int[uut.length];
        System.arraycopy(uut, 0, copiedUut, 0, uut.length);
        Arrays.sort(copiedUut);

        // Actual method execution
        selectionSort.sort(uut);
        actual = Arrays.compare(copiedUut, uut);

        // Verification
        SelectionSortImpl.printArray(uut);
        SelectionSortImpl.printArray(copiedUut);
        Assertions.assertEquals(expected, actual);
    }

    private int[] generateRandomArray(int noOfEntries) {
        return new Random().ints(0,350).limit(noOfEntries).toArray();
    }


    @Test
    public void sort_NON_EMPTY_SORTED() {
        uut = generateRandomArray(NO_OF_ENTRIES);
        Arrays.sort(uut);

        runTest();
    }

    @Test
    public void sort_NON_EMPTY_UNSORTED_DESCENDING() {
        uut = generateRandomArray(NO_OF_ENTRIES);
        Arrays.sort(new int[][]{uut}, Collections.reverseOrder());

        runTest();

    }

    @Test
    public void sort_ONE_ELEMENT_ONLY() {
        uut = generateRandomArray(1);

        runTest();
    }
}

PS: It is clear to me that I could manually go on the change lines private SelectionSortImpl selectionSort; and selectionSort = new SelectionSortImpl(); to AbstractSortImpl sorter; and sorter = new InsertionSortImpl(); respectively next time I have an implementations for InsertionSort. But this would be contrary to the idea of automated testing.

maz
  • 11
  • 2

0 Answers0