Luna
Luna

Reputation: 1488

Concise way of repeating multiple tests with same test data in JUnit

I have many tests - in different test classes - that should run using the same sets of sample data. Here is an example test method.

@Test
public void testTracerErrorPerPixel() {
    // Iterate over all sample images
    // ** This is the line I want to refactor out **
    for (Image image : SampleImages.values()) {

        // Do some tests on those images

        Assert.assertTrue("Tracer error in " + image + " too large after tracing, error per pixel is " + someValue, someValue);
    }
}

@Test
public void testTracerCorrectPixelPercent() {
    // Iterate over all sample images
    // ** This is the line I want to refactor out **
    for (Image image : SampleImages.values()) {

        // Do some different tests on those images

        Assert.assertTrue("Correct pixel percent in " + image + " too low after tracing, % correct " + someValue, someValue);
    }
}

Is there a standard more concise way of doing this? Having for (Image image : SampleImages.values()) { feels like the wrong way of doing this.

Using another framework such as TestNG would be acceptable.

Upvotes: 0

Views: 536

Answers (4)

cheffe
cheffe

Reputation: 9500

We are using the Parameterized runner for this matter. More information is found in the junit docs.

In your case you can write

import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

@RunWith(Parameterized.class)
public class ParameterTest {

    @Parameters
    public static Iterable<Object[]> data() {
        // extract to some class for readability and reuse
        return Arrays.asList(new Object[][] { 
                { new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB) }, 
                { new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB) } 
        });
    }

    private Image image;

    public ParameterTest(Image aImage) {
        image = aImage;
    }

    @Test
    public void testTracerErrorPerPixel() {
        // Do some tests on those images
        System.out.println(image);
    }

    @Test
    public void testTracerCorrectPixelPercent() {
        // Do some different tests on those images
        System.out.println(image);
    }
}

Upvotes: 1

Luna
Luna

Reputation: 1488

By swapping to TestNG, I was able to make use of DataProviders to clean this up.

This is the example from above, changed to use DataProviders.

@Test(
    dataProvider = "images",
    dataProviderClass = Images.class
)
public void testTracerErrorPerPixel(Image image) {
    // Do some tests on those images

    Assert.assertTrue("Tracer error too large after tracing, error per pixel is " + someValue, someValue);
}

@Test(
    dataProvider = "images",
    dataProviderClass = Images.class
)
public void testTracerCorrectPixelPercent(Image image) {
    // Do some different tests on those images

    Assert.assertTrue("Correct pixel percent too low after tracing, % correct " + someValue, someValue);
}

A DataProvider was also added in Images.class.

@DataProvider(
        name = "images",
        parallel = true
)
public static Object[][] createImages() {
    // Make the array of images
}

I'll accept this answer tomorrow unless someone else provides an answer that works without swapping to TestNG.

Upvotes: 1

Nikhil Joshi
Nikhil Joshi

Reputation: 817

package stackoverflow.q_24932384;

import org.junit.Test;

import junit.framework.TestCase;

public class CommonJUnitData extends TestCase{
    private boolean areImageEqual= false;

    @Override
    protected void setUp() throws Exception {
        //Your image code which will set value of areImageEqual value, like:
        areImageEqual = compare.compare(original, tracedAndRedrawn);
    }

    @Test
    public void testTracerError() {
        //Use areImageEqual variable value
    }
}

Upvotes: 0

JamesB
JamesB

Reputation: 7894

I would refactor this test as follows:

@Test
public void testVectorError() {
    // Iterate over all sample images
    for (Image image : SampleImages.values()) {

        PixelComparer comparer = compare(image);

        // Ensure that traced image is close to original image
        Assert.assertTrue("", comparer.rootMeanSquareErrorPerPixel < 0.01d);
    }
}

private PixelComparer compare(Image image) {

    Pixels original = image.getPixels();

    // Trace image to vector
    Tracer tracer = new Tracer();
    tracer.trace(pixels);

    // Redraw image at same resolution
    Pixels tracedAndRedrawn = tracer.render(original.width, original.height);

    PixelComparer comparer = new PixelComparer();
    comparer.compare(original, tracedAndRedrawn);

    return comparer;
}

The compare method could either be an internal method to the test class (as shown) or placed into a test utility class and then re-used by multiple test classes.

I think it is important to apply the DRY principle to tests as well as application code. That is what is important here, not what tool you use (JUnit, TestNG).

Upvotes: 0

Related Questions