I'm using Java to code a project in spring boot with Mockito. I'm new to Mockito, and I'm having trouble understanding how to mock inner classes that are causing the test class to fail. The methods for the inner classes are very complex, and I just need them to return an object of type ReturnData, whose value I choose. Example code is shown below:
public class class1() {
public void methodToBeTested() {
...
ReturnData rd = class2.method(...); //Not getter or setter, a method that has its own functionality
...
}
public void testClass1Method() {
class2 c = mock(class2.class);
class1ReturnType t = class1.methodToBeTested(c);
//Confused on what follows, need class2 method to return what I want it to return. I need to mock it, I have no other choice, but don't know how to access it
}
}
I have been scouring Stack Overflow, but can't find anything that answers my question, and I don't know if this is even possible. I need to somehow access class2 and have its method return different ReturnData values depending on what I'm testing for in the unit test. There are multiple classes called in the class1 method, but I'm only showing one for clarity.
When thenReturn will solve this problem, but only if there are no bugs in the internal classes, which does not apply to my situation unfortunately
Related
I need mock some class with final method using mockito. I have wrote something like this
#Test
public void test() {
B b = mock(B.class);
doReturn("bar called").when(b).bar();
assertEquals("must be \"overrided\"", "bar called", b.bar());
//bla-bla
}
class B {
public final String bar() {
return "fail";
}
}
But it fails.
I tried some "hack" and it works.
#Test
public void hackTest() {
class NewB extends B {
public String barForTest() {
return bar();
}
}
NewB b = mock(NewB.class);
doReturn("bar called").when(b).barForTest();
assertEquals("must be \"overrided\"", "bar called", b.barForTest());
}
It works, but "smells".
So, Where is the right way?
Thanks.
From the Mockito FAQ:
What are the limitations of Mockito
Cannot mock final methods - their real behavior is executed without any exception. Mockito cannot warn you about mocking final methods so be vigilant.
There is no support for mocking final methods in Mockito.
As Jon Skeet commented you should be looking for a way to avoid the dependency on the final method. That said, there are some ways out through bytecode manipulation (e.g. with PowerMock)
A comparison between Mockito and PowerMock will explain things in detail.
You can use Powermock together with Mockito, then you do not need to subclass B.class. Just add this to the top of your test class
#RunWith(PowerMockRunner.class)
#PrepareForTest(B.class)
#PrepareForTest instructs Powermock to instrument B.class to make the final and static methods mockable. A disadvantage of this approach is that you must use PowerMockRunner which precludes use of other test runners such as the Spring test runner.
Mockito 2 now supports mocking final methods but that's an "incubating" feature. It requires some steps to activate it which are described here:
https://github.com/mockito/mockito/wiki/What's-new-in-Mockito-2#mock-the-unmockable-opt-in-mocking-of-final-classesmethods
Mockito 2.x now supports final method and final class stubbing.
From the docs:
Mocking of final classes and methods is an incubating, opt-in feature. This feature has to be explicitly activated by creating the file src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker containing a single line:
mock-maker-inline
After you create this file you can do:
final class FinalClass {
final String finalMethod() { return "something"; }
}
FinalClass concrete = new FinalClass();
FinalClass mock = mock(FinalClass.class);
given(mock.finalMethod()).willReturn("not anymore");
assertThat(mock.finalMethod()).isNotEqualTo(concrete.finalMethod());
In subsequent milestones, the team will bring a programmatic way of using this feature. We will identify and provide support for all unmockable scenarios.
Assuming that B class is as below:
class B {
private String barValue;
public final String bar() {
return barValue;
}
public void final setBar(String barValue) {
this.barValue = barValue;
}
}
There is a better way to do this without using PowerMockito framework.
You can create a SPY for your class and can mock your final method.
Below is the way to do it:
#Test
public void test() {
B b = new B();
b.setBar("bar called") //This should the expected output:final_method_bar()
B spyB = Mockito.spy(b);
assertEquals("bar called", spyB.bar());
}
Mockito can be used to mock final classes or final methods. The problem is, this doesn't come as out of the box feature from Mockito and needs to be configured explicitely.
So, in order to do that,
Create a text file named org.mockito.plugins.MockMaker to the project's src/test/resources/mockito-extensions directory and add a single line of text as below
mock-maker-inline
Once done, you can use the mockito's when method to mock the behaviour like any other regular method.
See detailed examples here
I just did this same thing. My case was that I wanted to ensure the method didn't cause an error. But, since it's a catch/log/return method, I couldn't test for it directly without modifying the class.
I wanted to simply mock the logger I passed in. But, something about mocking the Log interface didn't seem to work, and mocking a class like SimpleLog didn't work because those methods are final.
I ended up creating an anonymous inner class extending SimpleLog that overrode the base-level log(level, string, error) method that the others all delegate to. Then the test is just waiting for a call with a level of 5.
In general, extending a class for behavior isn't really a bad idea, and might be preferable to mocking anyway if it's not too complicated.
I am working with legacy code and trying to write a unit test for an implementation I did. I have the following structure:
AbstractClass:
----------------
public AbstractClass {
abstract method2();
void method1(){
...does something...
..calls --> method2()
}
}
Subclass
------------
public Subclass extends AbstractClass(){
void method2(){
..do something....
..mockThisMethod()...
return true;
}
}
I have an abstract class which has some logic implemented in a specific method.
This method calls than another method implemented in the subclass. The method in the subclass calls other methods which I want to mock.
Is this possible without changing the implementation code (hard to change)?
Mos of the results are suggesting using mockito spying but it doesn't work.
I followed the TestDesign describer here:
https://www.tildedave.com/2011/03/06/pattern-stubbing-legacy-superclasses-with-mockito-spies.html
What I did is:
Subclass subclass= spy(Subclass.class);
when(subclass.mockThisMethod()).thenReturn(something);
subclass.method1() (I am not sure if this line is correct?)
So what I want to avoid is, calling the method (mockThisMethod) in the Subclass.
Since this method does some db-stuff an so on. I know it would be easier to test, if I use object composition instead of inheritance but at this point, it is hard to change the whole implementation. The code above is not working..I get a NPE.
1) You do not create a Spy by passing the class to the static Mockito.spy method.
Instead, you must pass an instance of that particular class:
Subclass subclassSpy = spy(new Subclass());
Also, consider using annotations:
#Spy
private Subclass subclassSpy = new Sublcass();
#Before
public void init(){
MockitoAnnotations.initMocks(this);
}
2) Avoid using when.thenReturn when stubbing a spy.
Instead, use doReturn..when..methodCall:
doReturn(something).when(sublcass).mockThisMethod();
otherwise you will invoke the actual method while stubbing and this may lead to unwanted behavior and/or exceptions.
I have a class Foo with private and public or protected methods. For example:
public class Foo{
private int number;
public Foo(){
setup();
doSthing();
}
private void doSthing(){
number=10;
}
public void setup(){
}
protected int getNumber(){
return number;
}
public void run(){
getNumber();
//Do blah blah...
}
}
And I am trying to test this class using Mockito.
public class FooTest
{
public void testMethods()
{
Foo foo = PowerMockito.mock (Foo.class);
//1 What should I do to see that setup() and doSthing()
//has been called on Foo construction
mock.run();
//2 What should I do to see that getNumber()
//has been called on run() method call
}
}
I am also hoping to include "times(1)" if possible. I'd appreciate your help.
You are getting this wrong:
First of all: please do not use any of the PowerMock... frameworks. They rely on byte code manipulation; and sooner or later that calls for trouble. Believe me, I have spent many hours hunting really strange errors for no good reasons.
Then: do not test your code this way!
You use a mocking framework to create/control those objects that you pass to your "class under test". You don't use the framework to directly test your "class under test"!
You also don't want to write test code that knows about private methods - those are implementation details.
What you do instead:
a) as said, you can use mocking to pass objects into your class under test. And then you can control/verify those mocks see the calls that you expect your "class under test" to make
b) you create objects of your "class under test" ... and then "assert" on the properties of those objects; or on results that method calls return.
Just to be precise: a mocked object ... doesn't know anything about the code in the "original" class. It is a mock! You can't use it for the kind of testing that your question implies you want to do. Either you call methods on your real class; or you specify something for a mock. But creating a mock to then "associate" it to the concrete class implementation ... is simply impossible.
Finally: if you think that your concrete class is actually "too big" to just be created the normal way for tests ... then chances are: your class is simply too big for anything else. Classes should be small; and their design should follow SOLID principles.
Long story short: don't try to force un-testable code into "tests", by using PowerMock... You better invest some more time to improve the quality of your production code; that will result in much higher "return on investment".
So, basically, a there is some poor code that I cannot change that needs to be tested. Traditionally, you inject your mocked dependencies, but with this code, I cannot do so, because there are no setter methods. Worse, the function I need to test calls a bunch of static factory methods-I can't just use the MockUp strategy to swap out the implementation there, because there is no class instance to be injected at all.
In C/++, you can retrieve a pointer to a function and know it's type by it's signature. If you changed the pointer, then you could potentially change how the stack was constructed by the compiler and you could pass function's around and all that Jazz.
Is there a way to use the Deencapsulation API to replace a static method implementation? Using this, I could write my own class, descend from the traditional, but return mocked objects in order that dependency injection still be achieved?
public class TestedClass {
public static void testedMethod() {
UnMockableType instanceVariable =
UnInjectableFactory.staticFactoryConstructor();
instanceVariable.preventControlFlowInfluenceThroughMocking();
}
}
Easy enough:
#Test
public void exampleTestUsingAMockUp()
{
new MockUp<UnMockableType>() {
#Mock
void preventControlFlowInfluenceThroughMocking() {}
};
TestedClass.testedMethod();
}
Above, UnInjectableFactory isn't mocked because it doesn't need to be (assuming it simply instantiates/recovers an UnMockableType).
It could also be done with #Mocked and the Expectations API.
I have a looked at similar questions on this board, but none of them answer my question. This sound strange, but is it possible to mock out a constructor call on the object you're mocking.
Example:
class RealGuy {
....
public void someMethod(Customer customer) {
Customer customer = new Customer(145);
}
}
class MyUnitTest() {
public Customer customerMock = createMock(Customer.class)
public void test1() {
//i can inject the mock object, but it's still calling the constuctor
realGuyobj.someMethod(customerMock);
//the constructor call for constructor makes database connections, and such.
}
}
How can I expect a constructor call? I can change the Customer constructor call to use newInstance, but im not sure if that will help. I have no control over what the body of the new Customer(145) constructor does.
Is this possible?
you can do so with EasyMock 3.0 and above.
Customer cust = createMockBuilder(Customer.class)
.withConstructor(int.class)
.withArgs(145)
.addMockedMethod("someMethod")
.createMock();
You can't do this with easymock, as it doesn't support mocking constructors. There's a library called powermock which can do that and is the only mocking library, as far as I know, that can stub constructors and static methods in Java.
import static org.powermock.api.easymock.PowerMock.expectNew;
instance = new UsesNewToInstantiateClass();
expectNew(AnyOldClass.class).andReturn(anyClass);
And this is why you want to inject your dependencies (via Guice or similar package) instead of creating them inside your class.
Then you don't HAVE TO mock their construction.
This assumes (a) that this is your code that you can change, and (b) that the objects in question are complex enough that you should inject them. Constructing simple objects inside your class are fine, but then you shouldn't need to mock them.