PowerMock whenNew without #PrepareForTest? - java

This is my situation, I have 2 very simple classes:
public class B {
public void doSomething(){
System.out.println("doSomething B reached");
}
}
And:
public class A {
public void doSomething(){
B b = new B();
b.doSomething();
System.out.println("doSomething A reached");
}
}
I want to test method doSomething of class A with Mockito. Therefor, I want to mock an instance of class B and give this to A when it is instantiating class B. I don't want b.doSomething() to be reached at all, for isolation reasons.
I know I can reach this behaviour by creating the following unittest:
#RunWith(PowerMockRunner.class)
public class TestA {
#Test
#PrepareForTest(A.class)
public void testDoSomethingOfA() throws Exception{
A a = PowerMockito.spy(new A());
B b = PowerMockito.mock(B.class);
PowerMockito.whenNew(B.class).withNoArguments().thenReturn(b);
a.doSomething();
}
}
which results in output:
doSomething A reached
So this work! However, my problem now is that we use the Jococo plugin for test coverage. Jococo doesn't cover code tested with the #PrepareForTest(A.class) statement. And my company values accurate code testing coverage.
My question: Is there another way around to give A an instantiation of B without having to use the #PrepareForTest statement?
Many thanks in advance!

To answer my own question, yes, use an agent: https://github.com/jayway/powermock/wiki/PowerMockAgent

#Rens Groenveld: After integrating PowerMockAgent, did you make any changes in your test class or source code ? I tried integrating PowerMockAgent and removed my main source class from #PrepareForTest but the behavior is same (creating new instance instead of mock).
I have tried jacoco offline instruments and many other solution, It did not work.
I can not post to your comment (needs 50 points) hence added as answer.

Related

Run same Junit Test with multiple objects derived from same interface

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.

How to have multiple setups for different sets of JUnit Tests?

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
}

Unit tests, can you test a single method?

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.

Abstracting a Test Class

I have a few tests right now that uses PowerMock and Mockito to "mock objects". The problem is, all those tests create the same mocks over and over again. Is it possible to have an abstract class from which my test derive that pre-mocks these objects ?
Example :
public abstract class AbstractTest {
public void initialize() {
PowerMockito.mockStatic(StaticMock.class);
when(StaticMock.doSomething()).thenReturn(true);
}
}
#RunWith(PowerMockRunner.class)
#PrepareForTest(StaticMock.class) // BanManager.class contains static methods
public class Test extends AbstractTest {
#SuppressWarnings("serial")
#Test
public void testWithPerms() {
initialize();
SomeObject obj = new SomeObject();
obj.doSomething();
PowerMockito.verifyStatic();
Static.verifyIsCalled();
}
}
How could I do something like the above that actually worked ? This gives me Inconsistent stackmap frames
EDIT : Thank you for your answer. My problem was actually due to me using a PowerMock version incompatible with java 7. Still, your indication will be helpful.
Of course this is possible. If you put the #Before annotation on a method in the base class, it will run at the beginning of every test in any subclass. Alternatively, you can put this off in some kind of factory class that is used in all your tests.

Can I mock a super class method call?

Sometimes, you want to test a class method and you want to do an expectation on a call of a super class method. I did not found a way to do this expectation in java using easymock or jmock (and I think it is not possible).
There is a (relative) clean solution, to create a delegate with the super class method logic and then set expectations on it, but I don't know why and when use that solution ¿any ideas/examples?
Thanks
Well, you can if you want to. I don't know if you are familiar with JMockit, go check it out. The current version is 0.999.17 In the mean time, let's take a look at it...
Assume the following class hierarchy:
public class Bar {
public void bar() {
System.out.println("Bar#bar()");
}
}
public class Foo extends Bar {
public void bar() {
super.bar();
System.out.println("Foo#bar()");
}
}
Then, using JMockit in your FooTest.java you can validate that you're actually making a call to Bar from Foo.
#MockClass(realClass = Bar.class)
public static class MockBar {
private boolean barCalled = false;
#Mock
public void bar() {
this.barCalled = true;
System.out.println("mocked bar");
}
}
#Test
public void barShouldCallSuperBar() {
MockBar mockBar = new MockBar();
Mockit.setUpMock(Bar.class, mockBar);
Foo foo = new Foo();
foo.bar();
Assert.assertTrue(mockBar.barCalled);
Mockit.tearDownMocks();
}
Expanding on #Cem Catikkas answer, using JMockit 1.22:
#Test
public void barShouldCallSuperBar() {
new MockUp<Bar>() {
#Mock
public void bar() {
barCalled = true;
System.out.println("mocked bar");
}
};
Foo foo = new Foo();
foo.bar();
Assert.assertTrue(mockBar.barCalled);
}
No need for the static class annotated with #MockClass, it is replaced by the MockUp class.
I don't think I'd mock out a super call - it feels to me like the behaviour there is part of the behaviour of the class itself, rather than the behaviour of a dependency. Mocking always feels like it should be to do with dependencies more than anything else.
Do you have a good example of the kind of call you want to mock out? If you want to mock out a call like this, would it be worth considering composition instead of inheritance?
There are several tests that do just that (ie specify an expected invocation on a super-class method) using the JMockit Expectations API, in the Animated Transitions sample test suite. For example, the FadeInTest test case.
No, there is no way of mocking super class methods with jMock.
However there is a quick-and-dirty solution to your problem. Suppose you have class A and class B extends A. You want to mock method A.a() on B. You can introduce class C extends B in your test code and override the method C.a() (just call super, or return null, id does not matter). After that mock C and use the mock everywhere, where you'd use B.
intercepting a super call is much too fine-grained. Don't overdo the isolation.

Categories