JMockIt Mock not being applied using Faking : Mocking parents of mocked classes - java

Ok... I have an answer... see below. Thanks to everyone that helped. I have updated the title as well to better reflect the issues.
UPDATE2: The constructor of the parent class of ClassNotUnderTest (which has parameters) is being called with null parameters, which in turn calls it's parent with the same null parameters, which ends up causing a null exception.
I have tried:
Making mocks of both parents, with only the constructor mocked and used one or both of them when trying out the test. The MockClassNotUnderTest still calls the real constructors.
I tried using the #Mocked annotation in the parameter list for the test method, because I don't really want anything back from those parents... Nope. Causes some other error I don't understand.
I tried putting a super(someParams) call in my $init function, but that won't compile.
HEEEEELLLLLPPPPP!!!!
UPDATE:
Ok, the root of my problem is not the implementation as shown below, but with the mock itself. When the MockClassNotUnderTest makes it's constructor call, it is calling the constructor of the real parent of ClassNotUnderTest. I tried also mocking ParentofClassNotUnderTest, but that just caused NullPointerExceptions... sigh. Still searching, I will post updates as they occur. Any suggestions are welcome.
I am fairly new to JMockIt, but my Java skills are not bad. I am trying to mock a dependency class of the class under test. It appears that the either the real method is being called, or maybe it is the super class (more likely). So any ideas on what I am doing wrong?
Now I know some might comment on how I am setting the error parameter, and how that might be applied etc, and I welcome the comments, but the main problem is that this code is not being mocked properly/at all as far as I can see.
To answer a few questions up front... Yes I searched here, and yes I reviewed the tutorials/documentation at the JMockIt website... had both open as I wrote the code in the first place.
I have several similar situations to resolve, so any help is much appreciated. Thanks in advance.
Something like this:
public ClassUnderTest {
public someMethodUnderTest (){
<blah blah setup stuff>
try{
somevar = new ClassNotUnderTest(someParamA, someParamB, someParamC);
} catch(SomeExceptionA sea) {
System.out.printline("Go boom");
} <more catches here>
}
}
My test/mock classes are as follows (JUnit4/JMockIt):
public class TestClassUnderTest{
ClassUnderTest cut;
<Before method and constructor with some setup code for cut>
#Test public void test_someMethodUnderTest(){
MockClassNotUnderTest notUnderTest = new MockClassNotUnderTest();
notUnderTest.error = 1;
try{
testResults = cut.someMethodUnderTest();
} catch( SomeExceptionA sea) {
<test that it went boom>
}
}
public class MockClassNotUnderTest extends MockUp<ClassNotUnderTest> {
public int error = 4;
#Mock
public void $init(someParamA, someParamB, someParamC) throws SomeExceptionA, SomeExceptionB, SomeExceptionC {
if(error == 0) { thrown new SomeExeptionA(); }
else if(error == 1) { thrown new SomeExeptionB(); }
else if(error == 2) { thrown new SomeExeptionC(); }
else { }
}
}
}

My expectation would be that the new MockClassNotUnderTest() you are initializing in the test method does not share state with the new ClassNotUnderTest() that you are initializing in the production code.
Try making your error a static field, so that it is shared across objects being faked.
I have written a sample test case showing that your comment below is correct. I cannot replicate your problem unless you post real code... Here is my test:
public class FakeTest {
public static class Foo {
public void doSomething() {
try {
Bar b = new Bar(73);
} catch (Throwable t) {
System.out.println("Got a " + t.getClass());
}
}
}
public static class Bar {
private Integer param;
public Bar(Integer parameter) {
System.out.println("Got a real bar with param " + parameter);
this.param = parameter;
}
}
public static class MockBar extends MockUp<Bar> {
public int error = 4;
#Mock
public void $init(Integer parameter) {
System.out.println("Initing fake with parameter " + parameter);
if (error==1) {
throw new IllegalAccessError();
}
}
}
#Test
public void fakeTest() throws Exception {
System.out.println("Testing...");
MockBar mb = new MockBar();
mb.error=1;
Foo f = new Foo();
f.doSomething();
}
}
The output, as you would expect, is
Testing...
Initing fake with parameter 73
Got a class java.lang.IllegalAccessError

Think of this as a part II to the answer provided above.
What is provided there will successfully mock out a constructor. The root of my issue lay in the fact that my original MockClassNotUnderTest was calling the constructor of the REAL parent of ClassNotUnderTest. In faking this was not completely unexpected, so I made a mock of the parent... which the mock never called.
My original setup of the mocks (the MockBar mb = new MockBar() above) would have a line above it to setup the parent mock, which looked exactly the same, but with a different name. So I might have:
MockBarParent mbp = new MockBarParent();
MockBar mb = new MockBar();
mb.error = 1;
This did not work obviously... here's what did work:
Mockit.setUpMock(new MockBarParent());
MockBar mb = new MockBar();
mb.error = 1;
Now as for the why, I am not sure, but I can tell you this is how you setup a static mock.
One final word. These mocks will stay in memory when you do this. Be sure to call Mockit.tearDownMocks() before leaving the test function or it will persist into other tests. JUnit does not run tests in order, so this can cause all kinds of fun errors.
THANKS AGAIN FOR THE HELP!!!!! #dcsohl and Nicolas

Related

Refactoring static mocks in Mockito 3.4

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.

How to test behavior of parametrized constructor with JMockit? (New with JMockit)

I have a factory class which constructor takes two parameter. Depending on that parameters the factory creates four different types of classes or throws IllegalArgumentExceptions in case of invalid arguments.
First I need to test if the appropirate class is created depending on the given parameters.
Second I need to verify the correct Exception in case of invalid parameters.
For testing the correct class is build in the factory I can fake the expected class and verify their instantiation.
But I don't know how to deal with #Tested to set up specific parameters in the constructor.
I coudn't find any usable hint neither in the JMockit documentation nor by searching the internet.
Below is a sample factory class and a sample of a class created by the factory (the others are similar).
public class WorkerFactory {
private Worker worker;
public WorkerFactory(final String type, final String subtype) {
if(type == null) throw new IllegalArgumentException("type");
if(subtype == null) throw new IllegalArgumentException("subtype");
if(type.equals("One")) {
if(subtype.equals("A")) worker = new One_A();
else if(subtype.equals("B")) worker = new One_B();
else throw new IllegalArgumentException("subtype");
}
else if(type.equals("Two")) {
if(subtype.equals("A")) worker = new Two_A();
else if(subtype.equals("B")) worker = new Two_B();
else throw new IllegalArgumentException("subtype");
}
else throw new IllegalArgumentException("type");
}
public Worker getWorker() { return worker; }
}
public interface Worker {
public void doWork();
}
public class One_A implements Worker {
public void doWork() {
System.out.println(getClass().getName());
}
}
And a very stupid skeleton for the requiered test BUT without using JMockit.
package application;
import org.junit.Test;
public class WorkerFactoryTest {
WorkerFactory cut;
#Test
public final void testWorkerFactory() {
cut = new WorkerFactory("One", "A");
cut.getWorker().doWork();
cut = new WorkerFactory("One", "B");
cut.getWorker().doWork();
cut = new WorkerFactory("Two", "A");
cut.getWorker().doWork();
cut = new WorkerFactory("Two", "A");
cut.getWorker().doWork();
}
#Test
public final void testWorkerFactoryExceptions() {
try {
cut = new WorkerFactory("Three", "C");
} catch (Exception e) {
e.printStackTrace();
}
try {
cut = new WorkerFactory("One", "C");
} catch (Exception e) {
e.printStackTrace();
}
}
}
``
EDIT (2020.07.02):
The assertThrows(..) from JUnit is one way to verify exceptions. But I use still the old style try/catch variant encapsulated in functions like verifyNoException(errorMessage) with a fail(...) if i caught one or verifyXyzException(expectedExceptionMessage) with a fail(...) if I cought none. This gives me a better control over the exceptions I catch by even a good readability. A time ago i read about some drawbacks about assertThrows over the old fashin style but I can't remeber what they are.
Putting constructor logic in an init(..) method as suggested by JMockit is what I do indeed (the given example did not for simplification). But I still want to test the constructor and not the private initializer method(s). Also I prefere a design where a object gets fully initialized by constructor parameters because I don't like the (boring and ugly) setter calls.
And verifying the parameters passed in is even a good one in my opinion.
The #Tested annotation is useful in 90% of scenarios - empty constructor or constructors where all the args can be passed mocks via #Injectable. That's not the scenario you are in due to you trying to test the permutations through your constructor.
As an aside, JMockit is poking you and saying you might want to reconsider your design. For example, shift that constructor logic to an "init(..)" method (call it whatever) and you'd find things easier to work with, and likely a better overall design. Likewise, constructors-throwing-exceptions is poor design, which the init(..) would get you away from. But I digress...
Your testWorkerFactory(..) is fine as-is. There's no easy way to do permutations of constructor arguments, so what you've got is fine. Brute force is fine. Everything doesn't have to be JMockit, JUnit is still OK.
For testWorkerFactoryExceptions, I'd make use of assertThrows(..) as it is much cleaner and guarantees that you receive the expected throw.

Verifiying time between calls with mockito

I've read a lot of documentation, examples on the net, and still have no idea of how to do it. (if it could be done).
I need to test a method in a object called by other thread and it has a requirement of time. So my original idea was creating a spy, override the method and do the task, but the problem is, I can't access test method variables from the spy. So I can't get the value returned from System.currentTimeMillis() from the test method and proccess it to get the difference within times.
I will write some abstract code describing the situation so you could understand better the situation.
#Test
public void test()
{
Objectspied spy = Mockito.spy(new Objectspied(Parameters p));
long[] timesRetrieved = new long[numberOfCallsIExpect];
//here goes the tricky part
Mockito.doAnswer(new Answer<void>(){
#override
public methodCalledFromAnotherThread(int index)
{
//what i wish to do but can't do it
timesRetrieved[i] = System.currentTimeMilis();
}
}
).when(spy).methodCalledFromAnotherThread(anyInt);
//here initialize the thread who call it
//then proccess al time diferences and get sure they are what i've expected
}
public class AnotherThread
{
ObjectSpied reference;
public void run()
{
for (int i=0;i<repeat;i++)
{
reference.methodCalledFromAnotherThread(i);
Thread.sleep(1000);
}
}
}
I'm new to Mockito so i know syntax is totally wrong but i can fix that by myself, all i need to know is:
Is there any way to do it with Mockito?
If so, can you point me to the right direction?
You should be fine this way. Just make sure:
1) You mark the array as final
2) Properly implement the answer interface method
final long[] timesRetrieved = new long[size];
Mockito.doAnswer(new Answer<Void>() {
#Override
public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
int index = invocationOnMock.getArgumentAt(0, Integer.class);
timesRetrieved[index] = System.currentTimeMillis();;
return null;
}
}
).when(spy).methodCalledFromAnotherThread(Mockito.anyInt());

Encapsulating and mocking

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.

Are there some methods that can't be mocked by Mockito without the method being called on mock?

I'm new to Mockito, and think it rocks for mocking. I've just come across a case where it doesn't seem like i'm able to get it to work - that being, replacing a method of a normal object with a mock method, without the method getting called when I try to mock it.
Here's a super simplified example of what I'm trying to do, that sadly, doesn't duplicate the error, but seems to be exactly the same as my real code.
public class SimpleTest
{
public class A
{
}
public class B
{
public int getResult(A anObj)
{
throw new RuntimeException("big problem");
}
}
#Test
public void testEz()
{
B b = new B();
B spy = spy(b);
// Here are both of my attempts at mocking the "getResult" method. Both
// fail, and throw the exception automatically.
// Attempt 1: Fails with exception
//when(spy.getResult((A)anyObject())).thenReturn(10);
// Attempt 2: In my real code, fails with exception from getResult method
// when doReturn is called. In this simplified example code, it doesn't ;-(
doReturn(10).when(spy).getResult(null);
int r = spy.getResult(null);
assert(r == 10);
}
}
So currently when I run my test, the test fails by throwing an exception when I try and mock the "getResult" method of the spy. The exception is an exception from my own code (ie a runtime exception), and it happens when I try and mock the "getResult" method = ie when executing the "doReturn" line above.
Note that my real use case is more complex of course... the "B" class has lots of other methods that I want to leave as is, and just mock the one method.
So my question is how can I mock it so the method isn't called?
MAJOR NOTE: I just rewrote the entire test from scratch and it works fine now. I'm sure I had a bug in their somewhere, but it's not there now - the method isn't called when it's mocked using the spy! and for what it's worth, I'm using the doReturn syntax in mocking the method.
doReturn(10).when(spy).getResult(null);
Your reedited question works just fine now.
This commented line is wrong
when(spy.getResult((A)anyObject())).thenReturn(10);
Should be
when(spy.getResult(any(A.class))).thenReturn(10);
Full test (method isn't called)
public class SimpleTest {
public class A {
}
public class B {
public int getResult(A anObj) {
throw new RuntimeException("big problem");
}
}
#Test
public void testEz() throws Exception {
B b = new B();
B spy = spy(b);
doReturn(10).when(spy).getResult(null);
int r = spy.getResult(null);
assert (r == 10);
}
}
Result
Tests Passed: 1 passed in 0,176 s

Categories

Resources