I have a unit test (JUnit 4) with some pretty complex setup:
public class HDF5CompoundDSCutoffCachingBridgeTest {
protected final String TEST_PATH = "test-out.h5";
protected final DatasetName TEST_DS = new DatasetName("group", "foo");
protected WritableDataPoint testPoint1;
protected WritableDataPoint emptyPoint;
protected WritableDataPoint[] emptyPoints;
protected WritableDataPoint[] fullPoints;
protected IHDF5Writer writer;
protected HDF5CompoundDSBridgeConfig config;
protected HDF5CompoundDSCachingBridge<WritableDataPoint> dtBridge;
@Before
public void setUp() throws Exception {
try {
File file = new File(TEST_PATH);
testPoint1 = new WritableDataPoint(new long[][]{{1, 2}}, new long[][]{{3, 4}}, 6, 10l);
emptyPoint = new WritableDataPoint(new long[][]{}, new long[][]{}, 0, 0l);
emptyPoints = new WritableDataPoint[]{emptyPoint, emptyPoint, emptyPoint, emptyPoint, emptyPoint,};
fullPoints = new WritableDataPoint[]{testPoint1, testPoint1, testPoint1, testPoint1, testPoint1,};
config = new HDF5CompoundDSBridgeConfig(HDF5StorageLayout.CHUNKED,
HDF5GenericStorageFeatures.MAX_DEFLATION_LEVEL,
5);
writer = HDF5Writer.getWriter(file);
HDF5CompoundDSBridgeBuilder<WritableDataPoint> dtBuilder =
new HDF5CompoundDSBridgeBuilder<>(writer, config);
dtBuilder.setChunkSize(5);
dtBuilder.setStartSize(5);
dtBuilder.setTypeFromInferred(WritableDataPoint.class);
dtBuilder.setCutoff(true);
buildBridge(dtBuilder);
} catch (StackOverflowError e) {
// other stuff
}
}
protected void buildBridge(HDF5CompoundDSBridgeBuilder<WritableDataPoint> dtBuilder) throws Exception {
dtBridge = dtBuilder.buildCaching(TEST_DS);
}
// a bunch of tests follow
}
Now, I've subclassed the class that's under test here. It still needs the complex setup in the original test. It's behavior is pretty much the same -- it needs to do all of the things that the parent class does, plus it passes slightly different information to dtBuilder
.
I could just copy-paste the configuration code over. This does appeal to me a little bit: these are really two different objects under test, and it's possible that in the future their configuration needs will change. If they have completely separate setup code, then I can make changes to the way either object works without worrying about breaking tests unnecessarily. But that seems wrong.
What I've done instead is inherit from the class for the superclass:
public class HDF5CompoundDSAsyncBridgeTest extends HDF5CompoundDSCutoffCachingBridgeTest {
protected HDF5CompoundDSAsyncBridge<WritableDataPoint> dtBridge;
@Override
protected void buildBridge(HDF5CompoundDSBridgeBuilder<WritableDataPoint> dtBuilder) throws Exception {
dtBuilder.setAsync(true);
dtBridge = dtBuilder.buildAsync(TEST_DS);
assertNotNull(dtBridge);
}
// more tests go here
}
I like this because I get to verify that my new class still passes all of the tests its parent class did, but there seems to be something wrong about having unit tests inheriting from each other.
What's the right move here? I've read posts like this: What does “DAMP not DRY” mean when talking about unit tests? that suggest that inheriting for unit tests is a bad idea, but it seems wrong to copy + paste whole chunks of code, ever.