So I've started to layout unit tests for the following bit of code:
public interface MyInterface {
void MyInterfaceMethod1();
void MyInterfaceMethod2();
}
public class MyImplementation1 implements MyInterface {
void MyInterfaceMethod1() {
// do something
}
void MyInterfaceMethod2() {
// do something else
}
void SubRoutineP() {
// other functionality specific to this implementation
}
}
public class MyImplementation2 implements MyInterface {
void MyInterfaceMethod1() {
// do a 3rd thing
}
void MyInterfaceMethod2() {
// do something completely different
}
void SubRoutineQ() {
// other functionality specific to this implementation
}
}
with several implementations and the expectation of more to come.
My initial thought was to save myself time re-writing unit tests with something like this:
public abstract class MyInterfaceTester {
protected MyInterface m_object;
@Setup
public void setUp() {
m_object = getTestedImplementation();
}
public abstract MyInterface getTestedImplementation();
@Test
public void testMyInterfaceMethod1() {
// use m_object to run tests
}
@Test
public void testMyInterfaceMethod2() {
// use m_object to run tests
}
}
which I could then subclass easily to test the implementation specific additional methods like so:
public class MyImplementation1Tester extends MyInterfaceTester {
public MyInterface getTestedImplementation() {
return new MyImplementation1();
}
@Test
public void testSubRoutineP() {
// use m_object to run tests
}
}
and likewise for implmentation 2 onwards.
So my question really is: is there any reason not to do this? JUnit seems to like it just fine, and it serves my needs, but I haven't really seen anything like it in any of the unit testing books and examples I've been reading.
Is there some best practice I'm unwittingly violating? Am I setting myself up for heartache down the road? Is there simply a much better way out there I haven't considered?
Thanks for any help.
The AAA pattern is a common unit testing pattern. It is a way to arrange and organize test code to make unit tests clear and understandable, and consists of separating each unit test method into three sections: Arrange, Act, and Assert.
A unit test typically features three different phases: Arrange, Act, and Assert (sometimes referred to as AAA). For a unit test to be successful, the resulting behavior in all three phases must be in line with expectations.
ArchUnit is a small library that can be used to unit test the architecture and internal code quality of both small and large applications. With it, you can quickly, easily, and pragmatically begin to test your code quality objectives.
is there any reason not to do this?
No. Do it. Tests are classes for exactly this reason.
I haven't really seen anything like it in any of the unit testing books and examples I've been reading.
Keep reading. Introductions don't cover this.
Is there some best practice I'm unwittingly violating?
No.
Am I setting myself up for heartache down the road?
No.
Some folks get nervous about "brittle tests". You can find some questions here looking for ways to make it so a change to the software doesn't also lead to changes to the tests. In the long run, trying to create "robust" tests are silly. You want tests written so that every small change to the visible, interface level of the software requires test rewriting.
You want tests so that invisible, internal changes do not require test rewriting.
Use of classes and subclasses is orthogonal to those considerations.
Is there simply a much better way out there I haven't considered?
No. Object-orientation is the point. Tests are a class for exactly this reason.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With