I am trying to improve my knowledge about testing I'm trying to achieve running the same JUnit test class with different objects derived from the same interface.
so we can assume the following:
interface Base {
void sort();
}
class A implements Base {
#Override
public void sort() {
//sort naively
}
}
class B implements Base {
#Override
public void sort() {
//sort using another better approach
}
}
class C implements Base {
#Override
public void sort() {
//sort using optimized approach
}
}
class Test {
#Test
void test1() {
Base obj = new A();
obj.sort();
obj.otherStuff();
}
}
class SecondTest {
//trying to avoid making multiple test classes that has only one line in difference
#Test
void test1() {
var obj = new B();
obj.sort();
obj.otherStuff();
}
So my question is how to run the test class with the objects from A,B,C without falling into the trap of duplicate code and redundancy?
Please note that I wrote this example just to illustrate my point, and the sort() doStuff() methods are just placeholders but when you have over ~70 line of code duplication in each test class it starts to look ugly and redundant.
*I have looked at #beforeEach, #Before, #After and I don't think I see a way where those might help me.
You can write a parameterized test with a MethodSource.
#ParameterizedTest
#MethodSource("bases")
void test1(Base obj) {
obj.sort();
obj.otherStuff();
}
static Stream<String> bases() {
return Stream.of(new A(), new B(), new C());
}
A way to fix it is the following, you create a method within your test class that takes as input the Base obj and contains all the duplicate lines. What you'll do then is to initialize the obj in different tests, then pass it to the method.
Here is a code that would do the job:
class Test {
#Test
void test1() {
Base obj = new A();
wrapperMethod(obj);
}
#Test
void test2() {
var obj = new B();
wrapperMethod(obj);
}
public static void wrapperMethod(Base obj){
obj.sort();
obj.otherStuff();
}
}
As a rule of thumb, testing can be much like normal programming where redundancy is avoided with methods to guarantee reusability.
Cheers,
D
First of all you have to fix your understanding of what UnitTesting is about.
UnitTesting is not about code (coverage).
UnitTesing is about verifying desired public behavior where "public behavior means return values and/or communication with dependencies.
Each test method should verify a single atomic assumption of the tested units desired behavior.
From this point of view it does not make sense to pass a bunch of objects sharing the same interface trough the same test method since these different interface implementations exist to implements the interfaces methods with their own unique behavior. In turn the assumption how the objects behave differ uniquely.
If all the objects where expected to behave identically (which is the only assumption a single test method could verify) there where no different objects (i.e. implementations) in the first place.
Related
I have just started learning JUnit very recently and came across the following problem.
Have a look at the following class
class MyClass {
String a;
public MyClass(String a) {
this.a=a;
String doSomething(String a) {
if( a.isEmpty() )
return "isEmpty";
else
return"isNotEmpty";
}
I want to test the above method for both the conditions. If I proceed with the general structure of writing testcases it will look something like this:
class MyClassTest {
MyClass myClass;
#BeforeEach
void setUp() {
myClass=new MyClass("sampleString");
}
#Test
void doSomethingTest() {
Assertions.equal("isNotEmpty", myClass.doSomething());
}
}
However, for testing the empty string condition I will need another setup method where instead of "sampleString" I pass an empty string.
Following are the approaches I could think of and the questions for each:
Not use setUp at all and instead initialize the class in the individual test method. However, if let's say there are 10 testcases; 5 of which require empty string and rest "sampleString" then this doesn't make sense. Again, we can have a separate method for this repetitive code and call it individually in each testcase but then that defeats the purpose of having a steup method. Lets say I wanted to use two different setup methods, is there a way to do so?
Have a parameterized setup. I don't know if this is possible though. If yes, please share some useful links for this.
Use TestFactory. I tried reading up about this, but couldn't find an example for this specific case. If you have any, please share.
This example has been kept simple for illustrative purposes.
Group the tests with the same setup in an inner class annotated with #Nested. Each nested test class can have its own setup in a local #BeforeEach method.
You can always prepare the non-common data inside your test method. I've always thought it's easier this way, compared to using parameterized tests. You can't mix parameterized and non-parameterized tests in 1 file.
#Test
void doSomething_nullString()
{
myClass = new MyClass(null);
Assert.assertNull(myClass.doSomething());
}
#Test
void doSomething_emptyString()
{
myClass = new MyClass("");
Assert.assertEquals("", myClass.doSomething());
}
#Test
void doSomething_nonEmptyString()
{
myClass = new MyClass("sampleString");
Assert.assertEquals("sampleString", myClass.doSomething());
}
Or, you can always have helper methods inside the test class.
private MyClass createTestObject_nonNullString() {
return new MyClass("nonNullString");
}
private MyClass createTestObject_nullString() {
return new MyClass(null);
}
#Test
public void doSomething_sample() {
MyClass test = createTestObject_nonNullString();
// perform test
}
Imagine I had the following class structure:
class Parent {
public void method() {
// Some calculations
}
}
class Child extends Parent {
#Override
public void method() {
super.method();
// Some additional logic
}
}
I am spock-testing the Child.method and want to verify if the Parent.method is called from the Child.method. I did some research and i haven't found any satisfying solution to solve my problem.
How can I verify in a Spock test that in the call of Child.method the superclass method (Parent.method) was called as well?
Known solution: In Child move the super.method() to a separate, package-private method.
I want to know whether there is a better solution.
tim_yates commented:
Why do you want to test this? Can't you tell as the super class calculations were performed?
I completely agree. I would not test this because as #Override implies, the contract is an override, delegation to the super class method is optional. Why would you force your users to call the super class method? But as Tim said, you can test for the side effects which are important to you. Here is a little example with one side effect being a field assignment and another being something written to System.out (maybe silly, but just in order to show something non-obvious with a mock):
package de.scrum_master.stackoverflow.q60167623;
public class Parent {
protected String name;
public void method() {
// Some calculations
System.out.println("parent method");
name = "John Doe";
}
}
package de.scrum_master.stackoverflow.q60167623;
class Child extends Parent {
#Override
public void method() {
super.method();
// Some additional logic
System.out.println("child method");
}
public static void main(String[] args) {
new Child().method();
}
}
package de.scrum_master.stackoverflow.q60167623
import spock.lang.Specification
class ChildTest extends Specification {
static final PrintStream originalSysOut = System.out
PrintStream mockSysOut = Mock()
def setup() {
System.out = mockSysOut
}
def cleanup() {
System.out = originalSysOut
}
def test() {
given:
def child = new Child()
when:
child.method()
then:
1 * mockSysOut.println({ it.contains("parent") })
child.name == "John Doe"
}
}
Update: What you want to do simply is not possible technically, and for a reason: It would break encapsulation, see here, here, indirectly also here. The method is overridden, the word says it all. Test for the (side) effect or the result of a method, not for its interaction (that it is actually called). Spock's interaction testing capabilities are over-used even though the Spock manual warns about over-specification in some places. It just makes your tests brittle. Interaction testing is okay for design patterns like publish/subscribe (Observer pattern) where it makes sense to test the interactions between objects as such.
If you need to enforce that some functionality in Parent is called, you should enforce it via design not tests.
abstract class Parent {
public final void method() {
// Some calculations
additionalLogic();
}
protected abstract void additionalLogic();
}
class Child extends Parent {
#Override
protected void additionalLogic() {
super.method();
// Some additional logic
}
}
You could of course not make it abstract and just add a no-op implementation for additionalLogic() instead.
tim_yates and kriegaex are the big beasts in the jungle when it comes to good and bad Spock, or TDD-style testing generally ... they have more than once (rightly) picked apart my questions in the way they do here, basically on the basis of testing the code rather than the implementation.
Sometimes it's difficult though. Maybe there can be cases in which you would want to test for the calling of super.doSomething(). I am just putting together, using TDD, having already done a "spike", in which I rushed ahead without testing, an editor for a TreeTableView. The "spike" can be seen here. In a constructive comment to my answer, kleopatra advised me to check (i.e. put an if in the app code) to make sure that super.startEdit() had indeed started the editing of the cell before going further, so in this case it is not sufficient to test the "side-effect" of super.startEdit() as being that isEditing() now returns true. You genuinely need to know that your class's startEdit() actually does nothing more nor less than call super.startEdit().
However, I don't believe it can be done, and tim_yates or kriegaex would almost certainly have said how you could do that if it were possible.
My suggested TDD solution would therefore be something like this:
def 'super start edit should be called if cell is not empty'(){
given:
// NB has to be GroovySpy because isEmpty() is final
DueDateEditor editor = GroovySpy( DueDateEditor ){
isEmpty() >> false
}
when:
editor.startEdit()
then:
1 * editor.callSuperStartEdit()
}
class DueDateEditor extends TreeTableCell {
#Override
void startEdit(){
if( ! isEmpty() ) {
// this is the line you have to add to make the test pass
callSuperStartEdit()
}
}
def callSuperStartEdit(){
super.startEdit()
}
}
I think you have to "spawn" an artificial single-purpose method since there is, precisely, no side effect at all!
PS I will in fact parameterise this test so that it returns true to isEmpty() in the second call, and require the method NOT to be called in that case.
I´ve never used the Spock framework, but i think you can check the type of the instance in the Parent.method with instance of operator or reflection.
I might be asking something completely obvious. I do not have much experience in writing unit tests, and the following question came up which got me thinking.
Say, you have a class and this class has methods you want to test. But can you test a single method at once? I think not. In order to test the method, you need to invoke one or more other methods. For example:
class MyClass {
int x;
void foo() { x = 4; }
boolean bar() { x = 3; }
boolean check() { return x == 4; }
}
In order to test foo and bar, I need to use check() and on the other hand, in order to test check I need to use either foo() or bar().
Say, I have to following test case:
class MyClassTest {
#Test
void testFoo() {
MyClass obj = new MyClass();
obj.foo();
assert obj.check();
}
}
Now let's assume, my colleague changes the check() method:
boolean check() { return x == 5; }
Of course, the testFoo() will fail, and one might think that there is a problem with the foo method.
So this looks like a chicken-egg situation. How do people usually resolve this?
It probably doesn't make much sense to test methods independently here because the state of the class can change according to the sequence of methods called. In this case I'd make sure the behavior - or state transitions - work as expected. Please refer to the following three tests which properly specify the behavior of the class:
class WhenFooWasCalled {
#Test
public void ThenCheckShouldReturnTrue {
MyClass sut = new MyClass();
sut.foo();
assertTrue(sut.check());
}
}
class WhenBarWasCalled {
#Test
public void ThenCheckShouldReturnFalse {
MyClass sut = new MyClass();
sut.bar();
assertFalse(sut.check());
}
}
class WhenNothingWasCalled {
#Test
public void ThenCheckShouldReturnFalse {
MyClass sut = new MyClass();
assertFalse(sut.check());
}
}
Updated: I added a third test case: How does the check() behave if neither foo() nor bar() were called.
You don't write tests for individual methods - you write tests for individual requirements. In this case your class seems to have two requirements:
"check must return true when foo was called last"
"check must return false when bar was called last"
So you would write two unit-tests, one for each requirement to verify that the class fulfills it correctly (you might want to formulate a third requirement: what check is supposed to do when neither was called). When your colleague made the change above, he broke neither the foo method, not the check method. What he broke was the first requirement. Now he has to change the class somehow so that it fulfills it again. How he accomplishes this (change foo, change checkor both) doesn't matter.
This is common with a class with internal mutable state. I think your question reduces to your unit tests behaving properly after a given sequence of state manipulations.
What is the best way to write junit tests for interfaces so they can be used for the concrete implementing classes?
e.g. You have this interface and implementing classes:
public interface MyInterface {
/** Return the given value. */
public boolean myMethod(boolean retVal);
}
public class MyClass1 implements MyInterface {
public boolean myMethod(boolean retVal) {
return retVal;
}
}
public class MyClass2 implements MyInterface {
public boolean myMethod(boolean retVal) {
return retVal;
}
}
How would you write a test against the interface so you can use it for the class?
Possibility 1:
public abstract class MyInterfaceTest {
public abstract MyInterface createInstance();
#Test
public final void testMyMethod_True() {
MyInterface instance = createInstance();
assertTrue(instance.myMethod(true));
}
#Test
public final void testMyMethod_False() {
MyInterface instance = createInstance();
assertFalse(instance.myMethod(false));
}
}
public class MyClass1Test extends MyInterfaceTest {
public MyInterface createInstance() {
return new MyClass1();
}
}
public class MyClass2Test extends MyInterfaceTest {
public MyInterface createInstance() {
return new MyClass2();
}
}
Pro:
Need only one method to be implemented
Con:
Dependencies and mock objects of class under test have to be the same for all tests
Possibility 2:
public abstract class MyInterfaceTest
public void testMyMethod_True(MyInterface instance) {
assertTrue(instance.myMethod(true));
}
public void testMyMethod_False(MyInterface instance) {
assertFalse(instance.myMethod(false));
}
}
public class MyClass1Test extends MyInterfaceTest {
#Test
public void testMyMethod_True() {
MyClass1 instance = new MyClass1();
super.testMyMethod_True(instance);
}
#Test
public void testMyMethod_False() {
MyClass1 instance = new MyClass1();
super.testMyMethod_False(instance);
}
}
public class MyClass2Test extends MyInterfaceTest {
#Test
public void testMyMethod_True() {
MyClass1 instance = new MyClass2();
super.testMyMethod_True(instance);
}
#Test
public void testMyMethod_False() {
MyClass1 instance = new MyClass2();
super.testMyMethod_False(instance);
}
}
Pro:
fine granualtion for each test including dependencies and mock objects
Con:
Each implementing test class requires to write additional test methods
Which possibility would you prefer or what other way do you use?
Contrary to the much-voted-up answer that #dlev gave, it can sometimes be very useful/needful to write a test like you're suggesting. The public API of a class, as expressed through its interface, is the most important thing to test. That being said, I would use neither of the approaches you mentioned, but a Parameterized test instead, where the parameters are the implementations to be tested:
#RunWith(Parameterized.class)
public class InterfaceTesting {
public MyInterface myInterface;
public InterfaceTesting(MyInterface myInterface) {
this.myInterface = myInterface;
}
#Test
public final void testMyMethod_True() {
assertTrue(myInterface.myMethod(true));
}
#Test
public final void testMyMethod_False() {
assertFalse(myInterface.myMethod(false));
}
#Parameterized.Parameters
public static Collection<Object[]> instancesToTest() {
return Arrays.asList(
new Object[]{new MyClass1()},
new Object[]{new MyClass2()}
);
}
}
I strongly disagree with #dlev. Very often it is a very good practice writing tests that use interfaces. Interface defines contract between client and the implementation. Very often all your implementations must pass exactly the same tests. Obviously each implementation can have its own tests.
So, I know 2 solutions.
Implement abstract test case with various tests that use interface. Declare abstract protected method that returns concrete instance. Now inherit this abstract class as many times as you need for each implementation of your interface and implement the mentioned factory method accordingly. You can add more specific tests here as well.
Use test suites.
I disagree with dlev as well, there's nothing wrong with writing your tests against interfaces instead of concrete implementations.
You probably want to use parameterized tests. Here is what it would look like with TestNG, it's a little more contrived with JUnit (since you can't pass parameters directly to test functions):
#DataProvider
public Object[][] dp() {
return new Object[][] {
new Object[] { new MyImpl1() },
new Object[] { new MyImpl2() },
}
}
#Test(dataProvider = "dp")
public void f(MyInterface itf) {
// will be called, with a different implementation each time
}
Late addition to the subject, sharing newer solution insights
I'm also looking for a proper and efficient way of testing (based on JUnit) correctness of multiple implementations of some interfaces and abstract classes. Unfortunately, neither JUnit's #Parameterized tests nor TestNG's equivalent concept correctly fits my requirements, since I don't know a priori the list of implementations of these interface/abstract classes that might exists. That is, new implementations might be developped, and testers might not have access to all existing implementations; it is therefore not efficient to have test classes specify the list of implementation classes.
At this point, I have found the following project which seems to offer a complete and efficient solution to simplify this type of tests: https://github.com/Claudenw/junit-contracts . It basically allows the definition of "Contract Tests", through the annotation #Contract(InterfaceClass.class) on contract test classes. Then an implementer would create an implementation specific test class, with annotations #RunWith(ContractSuite.class) and #ContractImpl(value = ImplementationClass.class); the engine shall automatically apply any contract test that applies to ImplementationClass, by looking for all Contract Test defined for any interface or abstract class from which ImplementationClass derives. I have not yet tested this solution, but this sounds promising.
I have also found the following library: http://www.jqno.nl/equalsverifier/ . This one satisfies a similar though much more specific need, which is asserting a class conformity specifically to Object.equals and Object.hashcode contracts.
Similarly, https://bitbucket.org/chas678/testhelpers/src demonstrate a strategy to validate some Java fondamental contracts, including Object.equals, Object.hashcode, Comparable.compare, Serializable. This project use simple test structures, which, I believe, can be easily reproduced to suite any specific needs.
Well, that's it for now; I'll keep this post updated with other usefull informations I may find.
I would generally avoid writing unit tests against an interface, for the simple reason that an interface, however much you would like it to, does not define functionality. It encumbers its implementors with syntactic requirements, but that's it.
Unit tests, conversely, are intended to ensure that the functionality you expect is present in a given code path.
That being said, there are situations where this type of test could make sense. Assuming you wanted these tests to ensure that classes you wrote (that share a given interface) do, in fact, share the same functionality, then I would prefer your first option. It makes it easiest on the implementing subclasses to inject themselves into the testing process. Also, I don't think your "con" is really true. There's no reason you can't have the classes actually under test provide their own mocks (though I think that if you really need different mocks, then that suggests your interface tests aren't uniform anyway.)
with java 8 i do this
public interface MyInterfaceTest {
public MyInterface createInstance();
#Test
default void testMyMethod_True() {
MyInterface instance = createInstance();
assertTrue(instance.myMethod(true));
}
#Test
default void testMyMethod_False() {
MyInterface instance = createInstance();
assertFalse(instance.myMethod(false));
}
}
public class MyClass1Test implements MyInterfaceTest {
public MyInterface createInstance() {
return new MyClass1();
}
}
public class MyClass2Test implements MyInterfaceTest {
public MyInterface createInstance() {
return new MyClass2();
}
#Disabled
#Override
#Test
public void testMyMethod_True() {
MyInterfaceTest.super.testMyMethod_True();
};
}
Referred this question first. But seems my context is different.
I'll try to be short and simple. (Just the code I'm putting out is quite big ;)
I have some 50+ service classes. And need to write the unit test cases for all of them.
Across all these test classes, some tests are common. (delete, find etc) Just the object type would differ across the service classes.
Following example would clear the picture.
Consider following service class which has CRUD operations.
public class ObjService {
public Obj addObj(ParamType param, String var) { ... }
public void deleteObj(ParamType param, String var) { ... }
public List<Obj> findAllObj(ParamType param, String var) { ... }
public Obj findById(ParamType param, String var, String objIdToFind) { .. }
public List<Obj> getAllObjs(ParamType param, String var, ObjQuery objQuery) throws Exception { ... }
public Obj updateObj(ParamType param,
String var, Obj objToUpdate) throws Exception { }
}
Now I'm writing a test case for ObjService class. (Test Framework - testNG)
public class ObjServiceTest {
//These methods which will differ across all service classes
#Test
public void testAddObj() throws Exception {
addObj();
}
#Test
public void testUpdateObj() throws Exception {
Obj objToUpdate = addObj();
Obj updatedObj = updateObj(objToUpdate);
}
public Obj addObj() throws Exception {
//add obj test data and return the obj object
}
public Obj updateObj(Obj objToUpdate) throws Exception {
//update obj test data and return the updated obj object
}
//Following methods will be common to all classes. Except the name 'obj'
//e.g. For obj2 it would change to testDeleteObj2() { Obj2 obj2Todelete.... etc}
#Test
public void testDeleteObj() throws Exception {
Obj objToDelete = addObj();
deleteObj(objToDelete);
}
public void deleteObj(Obj objToDelete) throws Exception {
//delete the obj object
}
#Test
public void testFindById() throws Exception {
ObjService client = new ObjService();
List<Obj> objs = dsClient.findAllObj(...);
}
#Test
public void testFindAllObjs() throws Exception {}
#Test
public void testGetObjs() throws Exception {}
}
Now. Writing the common methods manually for all classes is surely a time consuming job. So can it be reduced by doing some automation?
(Tried my best to put the question in least baffling way)
Edit: 1) The test classes already inherit a BaseTestClass which contains the initial setup needed. So that is a problem.
2) Please don't forget the part, where
refactoring is needed across the
methods which differ.
It sounds like your services should implement some generic interface. That way you could write an abstract base test case which is also generic, then make each "real" service test inherit from it, including inheriting the tests within that abstract class.
The constructor for the subclass would pass in the appropriate values for things like the service, a sample query etc.
EDIT: For the base class, just make the abstract base test class subclass your existing base class.
For specialization, either override the test method itself when it needs to do a completely different thing, or make the test methods depend on abstract methods in the abstract class, so that each concrete subclass can fill in the appropriate behaviour.
A good first step would be to make a base Test class which handles the common methods, and then derive specific Test classes from that base class to test the methods which differ per service.
You could make the base Test class a generic class which takes your service objects as a generic parameter. You may want or need to make your service classes implement a common interface, so that you can test the common methods in a consistent, type-safe manner.
Create an abstract class that contains all tests that are common to all Services.
Include abstract method definitions for the methods that have to be implemented differently in each test class.
Now create all your test classes as subclass of this abstract class, implementing only what's needed for the individual Service.
One possible solution could be to genericize your test cases with the object type as generic type parameter. Possibly having a generic base test class, and instantiating it with the needed concrete type(s) in each separate test subclass. I did it in a somewhat similar case and it worked out well.
Eventually, if you have much duplicated functionality to test, consider refactoring your tested classes (possibly using generics as well) to eliminate duplication. However, write the unit tests first to ensure that you aren't breaking anything during the refactoring.