I have the following structure:
class Bar{
....
protected void restore(){
....
}
....
}
This class is extended by Foo as below:
class Foo extends Bar{
....
#Override
public void restore(){ //valid override
super.restore();
....
}
}
In my jUnit test I would like to test that when foo.restore() is called, the super.restore() is called subsequently. Hence, below is my jUnit test method:
class FooTest{
#Tested
Foo _foo;
#Test
void testRestore(final Bar bar){
new Expectations(){{
bar.restore(); times = 1; // Error! bar.restore() not visible
}};
Deencapsulation.invoke(_foo,"restore");
}
}
Unfortunately, my test cannot compile. The reason is that 1) the restore() of the parent is protected and 2) FooTest and Foo exist together in a separate project (and therefore folder) vs. Bar.
Is there anyway to achieve the desired test? I have checked the jMockit tutorials (many times over the past few months) and have not seen a similar test (same goes for a search on Google).
Update
With the help of the responses, I understand that enforcing subclasses to invoke super is not the best practice, yet this is not my implementation and I still have to test it. I am still looking for a way to enforce my jUnit test to check if the call to the parent is taking place.
So basically you are trying to enforce a contract of calling the super and trying to allow for subclassing? I think that this is not easily done due to the dynamic dispatch that will hide the behavior in Java. I don't think that Mocking will catch this.
A way the ensure that the super is called would be to break out the super and the extension into 2 methods like
class Foo {
public final void restore() {
//parent code...
doRestore();
}
protected void doRestore() {
//empty base implementation
}
}
class Bar extends Foo {
protected void doRestore() {
//do my subclass specific restore stuff here
}
}
The following test should work:
public class FooTest
{
#Tested Foo _foo;
#Test
void restoreInFooCallsSuper(#Mocked final Bar bar)
{
new Expectations() {{
invoke(bar, "restore");
}};
_foo.restore();
}
}
The super.restore() is supposed to do something useful no? some specific logic. In your test simply test that the outcome of invoking the super.restore() happened.
Another way to look into it is the following. In the subclass before doing anything you implement an assert that ensures that the super did its job correctly. This is a stronger check and is well known as part of Meyer's Design by Contract paradigm. In this context the subclass simply checks that the post-condition of the super.restore() implementation holds before executing and by using assert you know it will fail during Unit Tests but also during test integration runs of your application e.g.
class Foo extends Bar{
....
#Override
public void restore(){ //valid override
super.restore();
assert super_restore_worked_ok_condition : "restore post-condition failed";
....
}
}
Related
I have a Jupiter based UnitTest in a java project where I need to mock some static methods of an external utility. Mockito 3.4 allows for mocking static methods, so no need for PowerMock any more. We all use static mocks by defining them in a try(){} block and overwriting methods on those static mocks inside the block. All fine, but things sometimes get annoying when you have to implement a non trivial mocking cascade. Which is especially annoying of you have to do that in several test cases inside your test class.
class ClassA {
public static void methodA() { ... }
public static void methodB() { ... }
}
class ClassB {
public static void methodA() { ... }
public static void methodB() { ... }
}
class ClassC {
public static void methodA() { ... }
public static void methodB() { ... }
}
class ClassX {
public int doSomething() {
// does something using static methods from classes ClassA, ClassB, ClassC
return 3;
}
}
A test class might (roughly) look like that (please excuse typos and nonsense, this is only meant as a demonstration, this is not working code):
#Test
void test_doSomething() {
int result = 0;
ClassX classX = new ClassX();
try (MockedStatic<ClassA> classAMockStatic = Mockito.mockStatic(ClassA.class);
MockedStatic<ClassB> classBMockStatic = Mockito.mockStatic(ClassB.class);
MockedStatic<ClassC> classCMockStatic = Mockito.mockStatic(ClassC.class)) {
// this is a block where static methods get overwritten, also some mocks are created
// this code does not make sense, it is just to demonstrate the issue of non trivial mocking scenarios
// situations like this often arise when mocking building patterns for example
classAMockStatic.when(ClassA::methodA).thenReturn("fooA");
ClassB classBMock = mock(ClassB.class);
when(classBMock.methodA()).thenReturn("barA");
classAMockStatic.when(ClassA::methodB).thenReturn(classBMock);
ClassC classCMock = mock(ClassC.class);
when(classCMock.someMethodA()).thenReturn("abc");
when(classCMock.methodA()).thenReturn("barA");
classAMockStatic.when(ClassA::methodA).thenReturn(classCMock);
// and so on and so on, you get the idea
result = classX.doSomething();
}
assertThat(result).equals(3);
}
Typically the question arises if this cannot be refactored to implement the mocking cascade only once. And use it in several test cases. I tried that, I was surprised to find that some of my overwritten methods worked as expected, but not all. I failed to find a working solution:
// THIS DOES NOT WORK
#Test
void test_doSomething() {
int result = 0;
ClassX classX = new ClassX();
try (MockedStatic<ClassA> classAMockStatic = createStaticMockA();
MockedStatic<ClassB> classBMockStatic = createStaticMockB();
MockedStatic<ClassC> classCMockStatic = createStaticMockC()) {
result = classX.doSomething();
}
assertThat(result).equals(3);
}
private MockedStatic<ClassA> createStaticMockA() {
MockedStatic<ClassA> classAMockStatic = Mockito.mockStatic(ClassA.class);
classAMockStatic.when(ClassA::methodA).thenReturn("fooA");
ClassB classBMock = mock(ClassB.class);
when(classBMock.methodA()).thenReturn("barA");
classAMockStatic.when(ClassA::methodB).thenReturn(classBMock);
return classAMockStatic;
}
private MockedStatic<ClassB> createStaticMockB() {
MockedStatic<ClassB> classAMockStatic = Mockito.mockStatic(ClassB.class);
ClassB classBMock = mock(ClassB.class);
when(classBMock.someMethodA()).thenReturn("aaa");
when(classBMock.someMethodB()).thenReturn("bbb");
when(classBMock.methodA()).thenReturn("barA");
classBMockStatic.when(ClassB::methodA).thenReturn(classBMock);
return classBMockStatic;
}
private MockedStatic<ClassC> createStaticMockC() {
MockedStatic<ClassC> classAMockStatic = Mockito.mockStatic(ClassC.class);
ClassC classCMock = mock(ClassC.class);
when(classCMock.someMethodA()).thenReturn("abc");
when(classCMock.methodB()).thenReturn("barC");
classCMockStatic.when(ClassC::methodA).thenReturn(classCMock);
return classCMockStatic;
}
So this looks cleared up, but does not work.
I know that I obviously could just extract the mocking section into a method and call that first in the try block. But that separates the static setup from the mock generation. And it is not as clean as my idea.
Yes, I tried implementing an execution method which accepts a lambda holding the code actually meant to be executed. So that the try(){} block gets stowed away into a method, leaving only the call to that method with a lambda in the test case. Works, but is hard to read and to understand. Not a good solution in my experience.
And yes, I also know that one should try to refactor production code so that it is easier to mock it. Sometimes that is simply not possible (read: external dependencies).
So what are my questions here?
does anyone have an idea how to achieve a clean, refactored look which actually works?
can anyone explain to me why some of the overwritten methods work as expected while others don't? I know, all the examples on the internet demonstrate that you use the straight approach, but the examples are obviously showing trivial situations.
is it really true that no one else is annoyed by that situation of have to setup the mock cascade exactly where it confuses? And that you have to reimplement it for each test case?
As Tim Moore suggests, if you have:
class StaticUtil {
public static void foo() { ... }
}
You can introduce an interface and an implementation to inject into your clients:
interface Util {
void foo();
}
class DefaultUtil {
public void foo() {
StaticUtil.foo();
}
This makes writing tests simpler as you can just mock Util in the normal way.
I have the following class
public final class Foo {
private Foo() {}
public static void bar() {
if(baz("a", "b", new Object())) { }
}
private static boolean baz(Object... args) {
return true; // slightly abbreviated logic
}
}
And this is my Test:
#PrepareOnlyThisForTest(Foo.class)
#RunWith(PowerMockRunner.class)
public class FooTest {
#Test
public void bar() {
PowerMockito.mockStatic(Foo.class); // prepare
Foo.bar(); // execute
verifyPrivate(Foo.class, times(1)).invoke("baz", anyVararg()); // verify - fails
}
}
For that, I get the following error message - and I don't understand why...
Wanted but not invoked com.example.Foo.baz(
null );
However, there were other interactions with this mock.
Removing the prepare line above seems to make the verify line pass no matter for how many times you check for... :(
(Our SONAR code checks enforce that each test has some sort of assertXyz() in it (hence the call to verify()) and enforces a very high test coverage.)
Any ideas how to do this?
The problem with your code is that you mock Foo so your method implementations won't be called by default such that when you call Foo.call() it does nothing by default which means that it never avtually calls baz that is why you get this behavior. If you want to partially mock Foo, mock it using the option Mockito.CALLS_REAL_METHODS in order to make it call the real methods as you seem to expect, so the code should be:
#PrepareOnlyThisForTest(Foo.class)
#RunWith(PowerMockRunner.class)
public class FooTest {
#Test
public void bar() throws Exception {
PowerMockito.mockStatic(Foo.class, Mockito.CALLS_REAL_METHODS); // prepare
...
}
}
I have a problem with a class that I am testing where in almost every method I want to test, one of the first things each method does is call this one specific method. This method that is called once by all of these other methods takes a long time to execute. I don't want to have to wait for this every time I run my tests, it really is just a huge waste of time.
I attempted to #Spy the method using Mocktio, but I ran into problems because the really long method doesn't return anything. Can someone suggest a good way to mock out a single method inside a class I am trying to test?
Example:
public class myClass {
public void methodOne() {
reallyLongMethod();
// More code
}
public void methodTwo() {
reallyLongMethod();
// More code
}
.
.
.
public void methodN() {
reallyLongMethod();
// More code
}
public void reallyLongMethod() {
}
}
This is the class I am trying to test. I want to test all of the 'methodX()' methods. I don't want to run reallyLongMethod everysingle time however.
So, is there a way to use Mockito 'Spy' to stub out reallyLongMethod()? Even though it doesn'treturn anything?
You can use a Spy with doNothing(), but make sure you use the spy during the test. Mockito spies copy the original, instead of delegating to it.
#RunWith(MockitoJUnitRunner.class)
public class YourTest {
// Option 1:
// #Spy MyClass myClass = new MyClass();
// Option 2 (see #Before method)
MyClass myClass;
#Before public void ignoreReallyLongMethod() {
myClass = spy(new MyClass()); // discard original
doNothing().when(myClass).reallyLongMethod();
}
#Test public void methodOneWorks() {
myClass.methodOne(); // you're using the spy here
assertEquals(42, myClass.getFoo());
}
}
Though this does evoke a code smell, don't mock or stub the class under test, as long as you're careful to test the method behavior (methodOne) and not the stubbed behavior (reallyLongMethod) you'll be good to go. If you do want to test reallyLongMethod you'll want to use a different object instance or else you'll "test" the doNothing() call alone. Do bear in mind that if reallyLongMethod and your other methods have any negative interactions, these tests won't tell you about that.
By the way, you can also do the equivalent without using Mockito, which may make a little clearer what you are or aren't doing with your mocks:
#RunWith(JUnit4.class)
public class YourTest {
MyClass myClass;
#Before public void createMyClass() {
myClass = new MyClass() { // create an anonymous inner class
#Override public void reallyLongMethod() {} // that does nothing here
};
}
}
Sometimes when I write unit tests I should to mock reference to superclass.
I have read this question:
question
This answer answer with DI advice to refactor code. But I cannot it
this answer another answer is not suitable if superclass method is enough big. In my case I have very big code. Yes I know that it is brokes SOLID OOD principes but I just should to write test. I have not enough time for refactor.
said question was asked 4 years ago!
Does currently Mockito or Powermock can resolve this issue ?
update
code example:
class BaseService {
public void save() {
// a lot of code here! I cannot change this code.
}
}
public Childservice extends BaseService {
public void save(){
//logic for testing
super.save();
//logic for testing
}
}
update 2
public class Parent {
public int save() {
return 99;
}
}
public class Child extends Parent {
public int save() {
int i = super.save();
return i*2;
}
}
and test:
#RunWith(PowerMockRunner.class)
#PrepareForTest(Parent.class)
public class ParentTest {
#Test
public void testSave() {
PowerMockito.suppress(PowerMockito.methodsDeclaredIn(Parent.class));
System.out.println(new Child().save());
}
}
output: 198
With Powermock you can replace or suppress methods, so it is possible to change the action done by BaseService.save(). You can also make methods to do nothing with suppressing. You can even suppress static initializer blocks.
Please read this blog entry of the Powermock authors. See chapter "Replacing".
UPDATE:
Suppress seems to work for me, but replace not. See the picture below:
This is impossible; the whole point of a superclass is that it encapsulates upstream state and functionality, and the class hierarchy is hard-coded in your subclass based on the extends relationship.
I use Mockito 1.8.0 so I do not have AnyVararg. Upgrading to later version of Mockito is not on cards from my team at the moment. So please bear with me.
What the class looks like:
public abstract class Parent {
public void someMethod(String a, String b)
{
//.....
}
public void foo(String a, String... b)
{
//.....
}
}
public class Child extends Parent{
public void bar() {
someMethod(a,b);
foo(a,b,c);
methodToFailUsingSpy();
}
}
Unit tests
#Test
public void someTest() {
private spyOfChild = //initialize here;
doReturn("Something")).when(spyOfChild).methodToFailUsingSpy();
/* Tried using this, but did not help.
doCallRealMethod().when(spyOfChild).foo(anyString());
*/
spyOfChild.bar();
}
Problem -
When the spy sees someMethod(), it calls the real method in the abstract class. But when it sees foo(), it tries to find a matching stubbed method i.e control goes to Mockito's MethodInterceptorFilter, since it is not able to find a mock, it throws java.lang.reflect.InvocationTargetException.
I do not want foo() to be mocked. I want the real method to be called like it happens in someMethod(). Can someone explain if it is because of using method with variable length arguments with a spy?
This is a bug in Mockito.
https://groups.google.com/forum/#!msg/mockito/P_xO5yhoXMY/FBeS4Nf4X9AJ
Your example is quite complicated, to reproduce the problem is very simple:
class SimpleClass {
public String varargsMethod(String... in) {
return null;
}
public void testSpyVarargs() {
SimpleClass sc = Mockito.spy(new SimpleClass());
sc.varargsMethod("a", "b");
}
}
Even this will produce the error you describe, and the workaround suggested in the link doesn't work for me.
Unfortunately to get around this you will need to upgrade Mockito. Changing to version 1.9.5 makes the above run fine, plus you get the varargs matchers as you say (although note that your problem isn't to do with matchers but how Mockito handles spied varargs methods).
I don't think there were too many huge changes between 1.8.0 and 1.9.5, it shouldn't be too painful.