I had some needs to test complex legacy code with JUnit but it was very hard to isolate tests from their influence to each other. It was too expensive to find all internal influence points
so I wrote small Maven plugin called Jute, which allows to start every JUnit test method in external JVM process, also it allows to start test methods with different JVM and different JVM options.
The Project sources has been published in GitHub and 1.0.0 version has been published in Maven central
Showing posts with label testing. Show all posts
Showing posts with label testing. Show all posts
Sunday, May 17, 2015
Sunday, July 22, 2012
Visual testing of a triangle filling graphic method
Some time ago I was invited by a big company for a technical interview where I was asked by a test engineer - "how to write test for a method filling a triangle area?".. I didn't find the answer for the provided time (some inappropriate ideas like to use a neural network chased each other in my brain), but the problem was very interesting for me and an idea dawned me on the next day..
Idea: A Triangle is a very easy shape but it is very hard to distinguish the shape in an image by a computer, but a rectangle is much easier to be processed by a computer, thus we should just make a rectangle from two triangles and then we will check that the rectangle area is presented and artifacts-free, also we can check that there are not any points outside of the area..
I have written some Java code to check the idea. There is not a method in the java.awt.Graphics object to fill a triangle thus I have written such one:
Then I wrote a unit test to make the "visual check" of the method just on an image and it works well:
Idea: A Triangle is a very easy shape but it is very hard to distinguish the shape in an image by a computer, but a rectangle is much easier to be processed by a computer, thus we should just make a rectangle from two triangles and then we will check that the rectangle area is presented and artifacts-free, also we can check that there are not any points outside of the area..
I have written some Java code to check the idea. There is not a method in the java.awt.Graphics object to fill a triangle thus I have written such one:
public class TriangleFiller {
/**
* The method fills a triangle area and we check that the method fills a triangle
* @param graphics the graphics context
* @param xcoords an array contains the x coordinates for vertices (must have 3 positions)
* @param ycoords an array contains the y coordinates for vertices (must have 3 positions)
*/
public static void fillTriangle(final Graphics graphics, int[] xcoords, int[] ycoords) {
if (xcoords.length != 3 || ycoords.length != 3) {
throw new IllegalArgumentException("Triangle must have 3 points");
}
final Polygon polygon = new Polygon(xcoords, ycoords, 3);
// we need use draw+fill because the fill operation fills the inside area
graphics.drawPolygon(polygon);
graphics.fillPolygon(polygon);
}
}
Then I wrote a unit test to make the "visual check" of the method just on an image and it works well:
package com.igormaznitsa.testtriangle;
import java.awt.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.ImageIO;
import static org.junit.Assert.*;
import org.junit.Test;
public class TriangleFillerTest {
private boolean checkTriangleCornerPoints(final BufferedImage baseRGBImage, final int pointColor, final int[] xVerticies, final int[] yVerticies) {
for (int pointIndex = 0; pointIndex < 3; pointIndex++) {
final int x = xVerticies[pointIndex];
final int y = yVerticies[pointIndex];
if ((baseRGBImage.getRGB(x, y) & 0xFFFFFF) != pointColor) {
return false;
}
}
return true;
}
private boolean checkRectangleAreaHasBeenFilledOnly(final BufferedImage baseRGBImage, final int fillColor, final int backgroundColor, final int areaLeftX, final int areaTopY, final int areaWidth, final int areaHeight) {
final int areaRightX = areaLeftX + areaWidth;
final int areaBottomY = areaTopY + areaHeight;
final int imagewidth = baseRGBImage.getWidth();
final int imageheight = baseRGBImage.getHeight();
for (int y = 0; y < imageheight; y++) {
for (int x = 0; x < imagewidth; x++) {
final int rgb = baseRGBImage.getRGB(x, y) & 0xFFFFFF;
final boolean notInArea = x < areaLeftX || x > areaRightX || y < areaTopY || y > areaBottomY;
if (notInArea) {
assertEquals("Must be background color "+backgroundColor, backgroundColor, rgb);
} else {
assertEquals("Must be fill color " + fillColor, fillColor, rgb);
}
}
}
return true;
}
@Test
public void testFillTriangle_VisualTest() throws Exception {
// the graphic log image file
final File gfxLogFile = new File("./testimage.png");
// create a RGB memory rendered image which will be our base for the test
final BufferedImage baseTestImage = new BufferedImage(200, 200, BufferedImage.TYPE_INT_RGB);
final Graphics2D gfx = (Graphics2D) baseTestImage.getGraphics();
// we must disable antialasing for the graphics to avoid artefacts
((Graphics2D) gfx).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
final int backColor = 0x000000;
final int shapeColor = 0xFFFFFF;
// fill the image by our background color
gfx.setColor(new Color(backColor));
gfx.clearRect(0, 0, 200, 200);
// set the shape color
gfx.setColor(new Color(shapeColor));
// our triangles, we use non-equaterial triangles, to make a rectangle, not a square
final int[] firstTriangleX = new int[]{10, 10, 50};
final int[] firstTriangleY = new int[]{10, 150, 150};
final int[] secondTriangleX = new int[]{10, 50, 50};
final int[] secondTriangleY = new int[]{10, 10, 150};
// draw the first triangle
TriangleFiller.fillTriangle(gfx, firstTriangleX, firstTriangleY);
// save the current graphic state as an image (like log)
ImageIO.write(baseTestImage, "png", gfxLogFile);
assertTrue("The image must have set the points of vertices", checkTriangleCornerPoints(baseTestImage, shapeColor, firstTriangleX, firstTriangleY));
// draw the second triangle, to get a filled rectangular area on the image
TriangleFiller.fillTriangle(gfx, secondTriangleX, secondTriangleY);
gfx.dispose();
// save the current graphic state as an image (like log)
ImageIO.write(baseTestImage, "png", gfxLogFile);
assertTrue("Only the rectangle area must be filled, without artefacts",checkRectangleAreaHasBeenFilledOnly(baseTestImage, shapeColor, backColor, 10, 10, 40, 140));
}
}
Subscribe to:
Posts (Atom)