I am new to Java testing with JUnit. I have to work with Java and I would like to use unit tests.
My problem is: I have an abstract class with some abstract methods. But there are some methods which are not abstract. How can I test this class with JUnit? Example code (very simple):
abstract class Car {
public Car(int speed, int fuel) {
this.speed = speed;
this.fuel = fuel;
}
private int speed;
private int fuel;
abstract void drive();
public int getSpeed() {
return this.speed;
}
public int getFuel() {
return this.fuel;
}
}
I want to test getSpeed() and getFuel() functions.
Similar question to this problem is here, but it is not using JUnit.
In JUnit FAQ section, I found this link, but I don't understand what the author want to say with this example. What does this line of code mean?
public abstract Source getSource() ;
If you have no concrete implementations of the class and the methods aren't static whats the point of testing them? If you have a concrete class then you'll be testing those methods as part of the concrete class's public API.
I know what you are thinking "I don't want to test these methods over and over thats the reason I created the abstract class", but my counter argument to that is that the point of unit tests is to allow developers to make changes, run the tests, and analyze the results. Part of those changes could include overriding your abstract class's methods, both protected and public, which could result in fundamental behavioral changes. Depending on the nature of those changes it could affect how your application runs in unexpected, possibly negative ways. If you have a good unit testing suite problems arising from these types changes should be apparent at development time.
Create a concrete class that inherits the abstract class and then test the functions the concrete class inherits from the abstract class.
With the example class you posted it doesn't seem to make much sense to test getFuel() and getSpeed() since they can only return 0 (there are no setters).
However, assuming that this was just a simplified example for illustrative purposes, and that you have legitimate reasons to test methods in the abstract base class (others have already pointed out the implications), you could setup your test code so that it creates an anonymous subclass of the base class that just provides dummy (no-op) implementations for the abstract methods.
For example, in your TestCase you could do this:
c = new Car() {
void drive() { };
};
Then test the rest of the methods, e.g.:
public class CarTest extends TestCase
{
private Car c;
public void setUp()
{
c = new Car() {
void drive() { };
};
}
public void testGetFuel()
{
assertEquals(c.getFuel(), 0);
}
[...]
}
(This example is based on JUnit3 syntax. For JUnit4, the code would be slightly different, but the idea is the same.)
If you need a solution anyway (e.g. because you have too many implementations of the abstract class and the testing would always repeat the same procedures) then you could create an abstract test class with an abstract factory method which will be excuted by the implementation of that test class. This examples works or me with TestNG:
The abstract test class of Car:
abstract class CarTest {
// the factory method
abstract Car createCar(int speed, int fuel);
// all test methods need to make use of the factory method to create the instance of a car
#Test
public void testGetSpeed() {
Car car = createCar(33, 44);
assertEquals(car.getSpeed(), 33);
...
Implementation of Car
class ElectricCar extends Car {
private final int batteryCapacity;
public ElectricCar(int speed, int fuel, int batteryCapacity) {
super(speed, fuel);
this.batteryCapacity = batteryCapacity;
}
...
Unit test class ElectricCarTest of the Class ElectricCar:
class ElectricCarTest extends CarTest {
// implementation of the abstract factory method
Car createCar(int speed, int fuel) {
return new ElectricCar(speed, fuel, 0);
}
// here you cann add specific test methods
...
I would create a jUnit inner class that inherits from the abstract class. This can be instantiated and have access to all the methods defined in the abstract class.
public class AbstractClassTest {
public void testMethod() {
...
}
}
class ConcreteClass extends AbstractClass {
}
You could do something like this
public abstract MyAbstractClass {
#Autowire
private MyMock myMock;
protected String sayHello() {
return myMock.getHello() + ", " + getName();
}
public abstract String getName();
}
// this is your JUnit test
public class MyAbstractClassTest extends MyAbstractClass {
#Mock
private MyMock myMock;
#InjectMocks
private MyAbstractClass thiz = this;
private String myName = null;
#Override
public String getName() {
return myName;
}
#Test
public void testSayHello() {
myName = "Johnny"
when(myMock.getHello()).thenReturn("Hello");
String result = sayHello();
assertEquals("Hello, Johnny", result);
}
}
You can instantiate an anonymous class and then test that class.
public class ClassUnderTest_Test {
private ClassUnderTest classUnderTest;
private MyDependencyService myDependencyService;
#Before
public void setUp() throws Exception {
this.myDependencyService = new MyDependencyService();
this.classUnderTest = getInstance();
}
private ClassUnderTest getInstance() {
return new ClassUnderTest() {
private ClassUnderTest init(
MyDependencyService myDependencyService
) {
this.myDependencyService = myDependencyService;
return this;
}
#Override
protected void myMethodToTest() {
return super.myMethodToTest();
}
}.init(myDependencyService);
}
}
Keep in mind that the visibility must be protected for the property myDependencyService of the abstract class ClassUnderTest.
You can also combine this approach neatly with Mockito. See here.
My way of testing this is quite simple, within each abstractUnitTest.java. I simply create a class in the abstractUnitTest.java that extend the abstract class. And test it that way.
You can not test whole abstract class. In this case you have abstract methods, this mean that they should be implemented by class that extend given abstract class.
In that class programmer have to write the source code that is dedicated for logic of his.
In other words there is no sens of testing abstract class because you are not able to check the final behavior of it.
If you have major functionality not related to abstract methods in some abstract class, just create another class where the abstract method will throw some exception.
As an option, you can create abstract test class covering logic inside abstract class and extend it for each subclass test. So that in this way you can ensure this logic will be tested for each child separately.
You don't need a fancy Mockito add on, or anonymous classes, or whatever other things the other answers are recommending. Junit supports test classes extending each other: so, write a thorough, abstract test class (literally just make the test class abstract) for your abstract base class, that examines how each of the methods behave. Do these tests on a set of instance-variable objects, that are set up as you desire in an #BeforeEach method in this base test class. Have that method call an abstract allocateObjects() method, which will do all the object allocation.
Then, for each class that extends your abstract base, have a test class that extends the abstract test class you just wrote. This test class will do the actual object allocation in the overridden allocateObjects() method. The objects it allocates will be used by the methods in the parent test class: methods which are inhertied by this test class, and therefore run as a part of its testing.
Could you do factory tomfoollery? I guess: but since you probably need to create test classes for each subclass anyways, you might as well just keep things simple with inheritence. I suppose if you have a lot of subclasses, and none of them do anything that is worth testing appart from the superclass stuff, it would be worth it: but why on earth would you be creating subclasses in that case?
Instead of doing #inject mock on abstract class create a spy and create a anonymous implementation in the test class itself and use that to test your abstract class.Better not to do that as there should not be any public method on with you can do unit test.Keep it protected and call those method from implemented classes and test only those classes.
Related
I'm writing unit tests for a class with a dependency that extends a package-private abstract superclass. The set up is similar to the following:
package pkg1;
public class ConcreteClass<T extends Something> extends AbstractClass<T> {
...
}
package pkg1;
abstract class AbstractClass<T extends Something> {
public AbstractClass() {
...
}
protected abstract Object unusedAbstractMethod() {
...
}
public T foo() {
// this method kicks off another sequence of calls into other classes before returning
}
}
package pkg2;
#RunWith(MockitoJUnitRunner.class)
public class Test {
#Mock
private ConcreteClass<SomeClass> concreteClass;
#Test
public void test() {
when(concreteClass.foo()).thenReturn(someClass);
ClassUnderTest cut = new ClassUnderTest(concreteClass);
...
}
When the line when(concreteClass.foo()).thenReturn(someClass); is executed, the test is failing with a NullPointerException. From the stack trace, I can see that the logic in foo() is being executed and the NPE is being generated several layers deep in the resulting call stack. Why is the method actually being run on my mock, and how can I go about mocking it appropriately?
I think the mocking syntax you want is actually not:
when(concreteClass.foo()).thenReturn(someClass);
but instead:
when(concreteClass).foo().thenReturn(someClass);
The way you've written it, it's as if you're asking "concreteClass.foo()" to return the class whose type is mocked.
So say if concreteClass.foo() were some utility class you created that was implemented as { return SomeType.class }, then when(concreteClass.foo()) would give you a mock SomeType object.
I'm testing out an android app, and am using a library provided to me by my university, classes 1-4 come from my lecturer for our use.
I have a class structured like so:
ClassOne
public ClassOne {
private ClassTwo clsTwo;
...
public ClassOne(ClassTwo p1)
public ClassTwo getClsTwo();
}
ClassTwo is structured as so:
public ClassTwo {
private ClassThree clsThree;
...
public ClassTwo()
public ClassThree getClsThree();
}
ClassThree is structured as so:
public ClassThree {
private HashMap<Bitmap> mBitmaps;
...
private ClassFour clsFour;
...
public ClassThree(ClassFour p1);
...
public loadFile(String path, String name);
public loadFileFromAssetStore(String name);
}
ClassFour is structured as so:
public ClassFour {
...
public ClassFour(Context context);
...
}
The Class I am testing is ClassFive, which specifically has the methods highlighted which are causing issues:
public ClassFive {
private Bitmap myBitmap
...
public ClassFive(...,...,...,ClassOne p,...){
super(..., p,
p.getClsTwo().getClsThree().loadFileFromAssetStore("Default value"));
this.myBitmap = loadCorrectFile(...,p);
}
private Bitmap loadCorrectFile(..., ClassOne p){
String strCorrectFileName;
switch(...){
...
// set value of strCorrectFileName
...
}
this.myBitmap = p.getClsTwo().getClsThree().loadFileFromAssetStore(strCorrectFileName);
}
}
My problem is I need to test methods using constructor of ClassFive, however the tests are all 'falling over' when invoking the constructor with a NPE.
public class ClassFiveTest {
#Mock
private ClassOne mockClassOne = Mockito.Mock(ClassOne.class);
#Test
public void testConstructorGetName() throws Exception {
ClassFive instance = new ClassFive(..., mockClassOne);
...
// Assertions here
...
}
My problem is that a null pointer exception is being returned before my test can get to my assertions. Do I need to be using mockito? Because I tried that - maybe I'm just using it wrong for this instance. Or do I need to be using instrumented tests? When I tried instrumented testing I found it impossible to get access to ClassOne and ClassTwo?
This is easily remedied with some stubbing.
#Mock private ClassOne mockClassOne; // Don't call `mock`; let #Mock handle it.
#Mock private ClassTwo mockClassTwo;
#Mock private ClassThree mockClassThree;
#Override public void setUp() {
MockitoAnnotations.initMocks(this); // Inits fields having #Mock, #Spy, and #Captor.
when(mockClassOne.getClsTwo()).thenReturn(mockClassTwo);
when(mockClassTwo.getClsThree()).thenReturn(mockClassThree);
// Now that you can get to mockClassThree, you can stub that too.
when(mockClassThree.loadFileFromAssetStore("Default value")).thenReturn(...);
when(mockClassThree.loadFileFromAssetStore("Your expected filename")).thenReturn(...);
}
In summary, Mockito is designed for easily making replacement instances of classes so you can check your interactions with your class-under-test: Here, you're creating fake ("test double") implementations of ClassOne, ClassTwo, and ClassThree, for the purpose of testing ClassFive. (You might also choose to use real implementations or manually-written fake implementations, if either of those make more sense for your specific case than Mockito-produced implementations.) Unless you otherwise stub them, Mockito implementations return dummy values like zero or null for all implemented methods, so trying to call getClsThree on the null returned by getClsTwo causes an NPE until you stub getClsTwo otherwise.
If the stubs for mockThree change between tests, you can move them into your test before you initialize your ClassFive. I'm also sticking to JUnit3 syntax and explicit initMocks above, because Android instrumentation tests are stuck on JUnit3 syntax if you're not using the Android Testing Support Library; for tests on JUnit4 or with that library you can use a cleaner alternative to initMocks. Once you get comfortable with Mockito, you can also consider RETURNS_DEEP_STUBS, but I like to keep my stubs explicit myself; that documentation also rightly warns "every time a mock returns a mock, a fairy dies".
Isn't this long and complicated, and doesn't it feel unnecessary? Yes. You are working around violations of the Law of Demeter, which Wikipedia summarizes (emphasis mine) as:
Each unit should have only limited knowledge about other units: only units "closely" related to the current unit.
Each unit should only talk to its friends; don't talk to strangers.
Only talk to your immediate friends.
Your problem and your verbose solution both stem from ClassFive depending on ClassThree, but only via ClassOne and ClassTwo implementation details. This isn't a strict law, but in your own code outside of university you might treat this as a sign to revisit the designs of ClassOne, ClassTwo, and ClassFive and how they interact. If ClassFive were to depend directly on ClassThree, it may be easier to work with the code in production and tests, and maybe you'd find that ClassOne isn't necessary at all.
// ClassFive doesn't just work with its dependency ClassOne, it works directly with its
// dependency's dependency's dependency ClassThree.
super(..., p,
p.getClsTwo().getClsThree().loadFileFromAssetStore("Default value"));
I'd like to support the answer of#JeffBowman by showing how the code could look like.
The proposed solution implies that you add another parameter to the constructors parameter list with is far to long already. Your code could be simplified by following the Favor composition over inheritance principle
Most parameters of the constructor in ClassFive are only there to be pass to the parent classes constructor.
In this situation it would be better not to inherit from that super class, but create an interface (e.g.: extract with support of your IDE) of the super class (lets call is SuperInterface that is implemented by both, the super class and CLassFive.
The you replace all the parameters that are passed to the super class by one single parameter of type SuperInterface.
Then you simply delegate all methods of SuperInterface that are not implemented by CLassFive directly to the SuperInterface instance.
This is what it would look like:
public interface SuperInterface {
// all public methods of the super class.
}
public class ClassFive implements SuperInterface{
private final SuperInterface superClass;
private final Bitmap myBitmap
public ClassFive(SuperInterface superClass ,ClassTree p){
this.superClass = superClass;
p.loadFileFromAssetStore("Default value"));
this.myBitmap = loadCorrectFile(...,p);
}
#Override
public void someMethodDeclaredInInterface(){
this.superClass.someMethodDeclaredInInterface();
}
}
This pattern also works vice versa if you don't like the duplicated method delegations all over your classes extending SuperInterface.
This alternative approach is useful if your specializations override just a few methods of the interface and almost all the same.
In that case the interface you create may not be implemented by the super class. The methods declared in the interface don't even need to be part of the super classes public methods. The interface only declares methods that the super class (should now better be called "generic class") needs to use the derived behavior.
This would look like this:
interface AnimalSound{
String get();
}
class DogSound implements AnimalSound{
#Override
public String get(){
return "wouff";
}
}
class CatSound implements AnimalSound{
#Override
public String get(){
return "meaw";
}
}
class Animal {
private final AnimalSound sound;
public Animal(AnimalSound sound){
this.sound = sound;
}
public String giveSound(){
return sound.get();
}
}
And this is how we use it:
List<Animal> animals = new ArrayList<>();
animals.add(new Animal(new DogSound()));
animals.add(new Animal(new CatSound()));
for(Animal animal : animals){
System.out.println(animal.giveSound());
}
I would like to test a class that is used as a wrapper that provides abstraction for the classes underneath.
That means that I need to create some objects inside that class, that is, I don't pass collaborators through constructor or some method.
For example, here's a wrapper class:
public class Abstraction {
private ComplexClass complex;
public class Abstraction(some parameters) {
complex = new Complex(parameters);
}
}
To be able to test this class I had an idea to create a method that will return an object of Complex class, like this:
public class Abstraction {
private ComplexClass complex;
public class Abstraction(parameters) {
complex = createComplex(parameters);
}
protected createComplex ComplexClass(parameters) {
return new ComplexClass(parameters);
}
}
The thing is, I cannot use Mockito to mock collaborators created inside constructor of class that I'm testing. How to overcome this?
My idea was to spy the SUT so that createComplex returns mock object, but I cannot do that because SUT needs to be created first. It's kind of a dead lock.
My final goal is to test whether some methods of collaborator classes were called.
What is the business advantage of testing this class? It doesn't implement an algorithm and it doesn't make a decision. As you say, it is only a wrapper.
You say that you want to test if certain methods are called but how does that help anybody? Surely a test that confirms that the methods were called in some situations and not others, in other words a test of the business logic, would be much more useful. The risk here is that you will end up with a complex test that is difficult to maintain and introduces inertia that will make future re-factoring much more difficult and expensive. What is the reward you are hoping foir that will make that risk worthwhile?
You could do it with a reasonably simple anonymous inner class in your test case
ComplexClass mock = Mockito.mock(ComplexClass.class);
Abstraction abstraction = new Abstraction("foo") {
#Override
protected ComplexClass createComplex(parameters) {
return mock;
}
};
assertTrue("bar", abstraction.doStuff());
You could implement a factory for your ComplexClass which you set on your Abstraction:
public class ComplexClassFactory {
public ComplexClass create(parameters) {
return new ComplexClass(parameters);
}
}
public class Abstraction {
private ComplexClassFactory complexClassFactory;
public void setComplexClassFactory(ComplexClassFactory complexClassFactory) {
this.complexClassFactory = complexClassFactory;
}
private ComplexClass complex;
public class Abstraction(parameters) {
complex = complexClassFactory.create(parameters);
}
}
One possibility is to extract an interface for the ComplexClass class (which I named Complex) and provide an alternate constructor used only for testing purposes to inject an instance of the newly created Complex interface:
public class Abstraction {
private Complex complex;
public Abstraction(String parameters) {
this.complex = new ComplexClass(parameters);
}
Abstraction(Complex complex) {
this.complex = complex;
}
public class ComplexClass implements Complex {
private final String parameters;
public ComplexClass(String parameters) {
this.parameters = parameters;
}
}
interface Complex {
}
}
This way you can create a mock for the Complex interface, use the constructor which receives a Complex instance and test the Abstraction class independently:
#Test
public void testAbstraction() {
Complex mock = Mockito.mock(Complex.class);
Abstraction abstraction = new Abstraction(mock);
}
How do I test the abstract class? I researched it and found I need to create a mock object, but how do I create a mock object? I have no idea, can somebody help please? For example this is my abstract class:
public abstract class Aging {
private int age;
public Aging(int age) {
setAge(age);
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
I tried to use this code to test the constructor:
#Test
public void testAgingConstructor() {
Aging a = new Aging(18);
a.setAge(19);
Aging b = new Aging(19);
assertEquals(b, a);
}
and I got a error message "Aging is abstract; cannot be instantiated". What should I do?
In order to instantiate your abstract class, you need to create a concrete subclass.
#Test
public void testAgingConstructor() {
class AgingSubclass extends Aging {
public AgingSubclass(int age) { super(age); }
}
Aging a = new AgingSubclass(18);
a.setAge(19);
Aging b = new AgingSubclass(19);
assertEquals(b, a);
}
I would create a new non abstract class that extends your abstract class.it would be am empty class except the header with the extends clause.
Then you wil will be able to test your methods implemented at the abstract class.
The question to ask yourself is :
Why do I need to test this class ?
Is it a class dedicated to be extended by some other modules ? then yes, you should test it by actually testing this usecase : extend your abstract class and verify the behavior you get is the intended one.
Is it a class that will be used in your module where you have some implementations ? Then you should most probably test the behaviour of those implementations and thus test the concrete classes.
All in all, what you'll end up testing is some concrete class that extend your abstract class.
Mocking allows you to do not care about the dependency of a class when testing it and has nothing to do with your problem.
And a nice trick you can use if you don't want to bother writing a concrete class is to leverage the use of anonymous classes :
#Test
public void testAgingConstructor() {
Aging a = new Aging(18){}; //Create anonymous subclass and instantiate it.
a.setAge(19);
Aging b = new Aging(19){};
assertEquals(b, a);
}
For your class it should be as follows. It shows how to implement abstract classes inline (curly brackets). If you have abstract methods in your abstract class, you have to override and implement them inside curly brackets.
#Test
public void testAgingConstructor(){
Aging a =new Aging(18) {};
a.setAge(19);
Aging b =new Aging(19) {};
assertEquals(b,a);
}
I have an interface called Relation, implemented by a class BasicRelation, and extended by subclasses (e.g. ParentChild, Sibling, Spouse). While developing my code, I realized that I often need a method which takes a String representation of a relation to create it. For example:
public class ParentChild implements Relation extends BasicRelation {
// e.g. "Jack is Emily's father. Jill is her mother." will return the list
// <ParentChild(Jack, Emily), ParentChild(Jill, Emily)>
static List<ParentChild> fromSentence(String s) {
...
}
}
Now, since I find myself needing this method (fromSentence(String)) in every class, except perhaps in BasicRelation, I would like to move it up the hierarchy. The problem is that the internal details of the method is subclass-dependent, so I can't have it as a static method in the interface Relation or the superclass BasicRelation.
Unfortunately, in Java, it is also not possible to have a static abstract method.
Is there any way to ensure that every subclass of BasicRelation (or every class implementing Relation) implements fromSentence(String)? If no, should I be designing this in a completely different way? I guess this last question is more of a request for design-advice than a question.
Why does the static method need to be in the interface? What's stopping you from having a 'Utility' class and having the method in there?
public class RelationUtility {
public static BasicRelation relationFactory(String asString) {
....
}
}
As a static method, there is no reason other than access to private members, which can also be accomplished by by 'default' permissions on those members....
You can try making the BasicRelation class an abstract class and use an abstract fromSentence(..) method. This would require the ParentChild class to override and implement the fromSentence method because you can't create an object for ParentChild without implementing fromSentence()
public abstract class BasicRelation extends Relation(){
public abstract List<..> fromSentence(String s);
}
public class ParentChild implements Relation extends BasicRelation {
fromSentence(){
//parentChild class's implementation
}
}
If I understood right... you can try an approach like this
public class BasicRelation {
public abstract List<ParentChild> fromSentenceInSubclass(s);
public List<ParentChild> fromSentence(String s){
fromSentenceInSubclass(s);
}
}
And then you could have:
public class SubclassRelation extends BasicRelation {
public List<ParentChild> fromSentenceInSubclass(s){
// do subclass relation stuff
}
}
You will probably need to change the code a bit and add some Generics around to make it happen the way you want.
Sotirios Delimanolis Factory suggestion might also be an option.
You can have the abstract class BasicRelation include the static method which throws an Exception. That way you will be forced to override (shadow) the static method in the subclasses when you use it.
Something like:
public abstract class BasicRelation {
public static List<..> fromSentence(String s) {
throw new RuntimeException();
}
}