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.
Related
Suppose I have class with simple dependency:
public interface Dependency {
int doSomething(int value);
void doMore(int value);
int doALotMore(int value);
}
public final class A implements SomeInterface {
private final Dependency dep;
public A (Dependency dep) {
this.dep = dep;
}
#Override
public int add(final int x) {
dep.doMore(x);
return x + dep.doSomething(x) + dep.doALotMore(x);
}
}
And I'm writing test using mocks:
public class TestA {
private Dependency mockDep;
private SomeInterface a;
#Before
public void setUp() {
mockDep = Mockito.mock(Dependency.class);
a = new A(mockDep);
}
#Test
public void shouldAdd() {
final int x = 5;
when(mockDep.doSomething(x)).thenReturn(6);
when(mockDep.doALotMore(x)).thenReturn(7);
int actual = a.add(x);
assertThat(actual, is(18));
verify(mockDep, times(1)).doSomething();
verify(mockDep, times(1)).doALotMore();
verify(mockDep, times(1)).doMore();
verifyNoMoreInteractions(mockDep);
}
}
So far so good.
So the question is: do we violate encapsulation of class A by verifying how exactly the dependency was used? Does it really needed to test that dependency was used in exactly that way? Shouldn't we test A like a black-box (delete verify invocations from test case and leave just assertThat)? And how to deal with dependencies in such case?
The reason I'm asking is that I caught myself writing good amount of verification dependency code and it seems that we start to test actual internal realization details about class. And I feel uncomfortable about that because when I will try to rewrite this realization details in another way I need to rewrite test cases although the result of add for example will be the same. If I would test my class as a black-box I can change realization details and still be sure that given input will give same output.
Or it is necessary to actually test exactly the realization details and that is the point of unit-test itself? It seems somewhat wrong for me.
Consider this test instead:
public class TestA {
private Dependency mockDep;
private SomeInterface a;
private final int x = 5;
#Before
public void setUp() {
mockDep = Mockito.mock(Dependency.class);
a = new A(mockDep);
when(mockDep.doSomething(x)).thenReturn(6);
when(mockDep.doALotMore(x)).thenReturn(7);
}
#Test
public void shouldAdd() {
int actual = a.add(x);
assertThat(actual, is(18));
}
}
It really depends on logic which you're testing. Since your example don't provide any context, I'll give you a case when I feel not only comfortable to test such interaction, but even mandatory:
Let's say you're testing authentication token validation. You pas some token to your validator and it returns true/false. Inside of your validator you're calling some jwt.validate or any other 3rd party hash validation method. In this case I need to know that this validator will be called every time, because I can introduce some if token == null condition inside which will bypass this validation call and just return false. Then your tests could still pass but your code is now vulnerable to timing attack.
It's one kind of example. The other type of test I'm comfortable of testing that way is so called border testing. I want to know that my class triggers stripe payment gateway - so I mock it and just make sure it gets called without checking anything sophisticated in this particular test.
I have some code like below.
#RetryOnFailure(attempts = Constant.RETRY_ATTEMPTS, delay = Constant.RETRY_DELAY, unit = TimeUnit.SECONDS)
public void method() {
// some processing
//throw exception if HTTP operation is not successful. (use of retry)
}
The value of RETRY_ATTEMPTS and RETRY_DELAY variable come from a separate Constant class, which are int primitive. Both the variable are defined as public static final.
How can I override these values while writing the unit testcases. The actual values increases running time of unit testcases.
I have already tried two approach: Both did not work
Using PowerMock with Whitebox.setInternalState().
Using Reflection as well.
Edit:
As mentioned by #yegor256, that it is not possible, I would like to know, why it is not possible? When these annotations get loaded?
There is no way to change them in runtime. What you should do, in order to make your method() testable is to create a separate "decorator" class:
interface Foo {
void method();
}
class FooWithRetry implements Foo {
private final Foo origin;
#Override
#RetryOnFailure(attempts = Constant.RETRY_ATTEMPTS)
public void method() {
this.origin.method();
}
}
Then, for test purposes, use another implementation of Foo:
class FooWithUnlimitedRetry implements Foo {
private final Foo origin;
#Override
#RetryOnFailure(attempts = 10000)
public void method() {
this.origin.method();
}
}
That's the best you can do. Unfortunately.
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
};
}
}
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.
I'm trying to write a unit test that needs to confirm if a method is called or not. I'm using JUnit, Mockito and PowerMock.
public class Invoice
{
protected void createInvoice()
{
// random stuff here
markInvoiceAsBilled("57");
}
protected void markInvoiceAsBilled(String code)
{
// marked as billed
}
}
So, here my system under test is Invoice. I'm running this test:
public class InvoiceTest
{
#Test
public void testInvoiceMarkedAsBilled()
{
Invoice sut = new Invoice();
Invoice sutSpy = spy(sut);
sut.createInvoice();
// I want to verify that markInvoiceAsBilled() was called
}
}
This example is just an example of what the actual code looks like....
My problem is that mockito says you can only verify if a method is called on a mocked object... but I don't want to mock this object, as it's my object under test. I know that you can spy on the object you're testing, so here's what I tried:
verify(sutSpy).markInvoiceAsBilled("57");
Is what I'm trying to do not possible? Or am I just going about it the wrong way?
Thanks everyone :)
I'm not sure if what you are attempting to do is the best way to go about things.
I wouldn't concern myself with verifying that Invoice.createInvoice() calls an internal, private method markInvoiceAsBilled() - instead test that calling createInvoice() changes the state of the Invoice object in the way you expect - i.e., that status is now BILLED or something similar.
In other words - don't test what methods are called by createInvoice() - test that after calling this method, the state of the object is what you expect.
I agree with matt-b's answer. That being said, depending on the use case and the complexity of the method, you can redesign your unit so that it can be tested.
Say for example your object gets much more complicated, e.g.
public A {
public a() {
b();
c();
}
public b() { /** hairy code, many branches to test */ }
public c() { /** hairy code, many branches to test */ }
}
Covering b with tests and c with tests is straight-forward, but covering a would seem like a hassle since you depend on methods b and c.
Consider instead this design
public A {
private final Dep mDep;
public a() {
mDep.b();
mDep.c();
}
public b() {
mDep.b();
}
public c() {
mDep.c();
}
// dependency abstraction we create to help test
static class Dep {
public b() { /** hairy code, many branches to test */ }
public c() { /** hairy code, many branches to test */ }
}
}
Now, testing A.a, A.b and A.c just requires you to verify your mDep is called (among whatever else the method does). Separately, you test A.Dep.b and A.Dep.c methods.