I'm writing unit tests for a block of code that uses introspection; specifically it calls getDeclaredField() on the class I want to mock and tries to get the value of the field. Is there a way to mock this with Mockito?
Mockito operates using the same introspection libraries you're trying to fool by creating a Mock. Even if you could cajole it to work, I'm not sure how easy it would be to understand or maintain.
I'd suggest creating a very small nested class and operating on it normally:
public class YourTest {
private static class SampleClass {
String field1;
int field2;
}
#Test public void introspectionWorks() {
yourSUT.process(new SampleClass());
}
}
Barring that, extract the difficult-to-mock call into a method you can stub easily:
public class YourSUT {
/* ... */
/* package */ Class<?> getFieldType(Object object, String fieldName) {
return object.getClass().getDeclaredField(fieldName).getType();
}
}
public class YourTest {
#Test public void introspectionWorks() {
YourSUT spy = Mockito.spy(yourSUT);
doReturn(String.class).when(spy).getFieldType(myObject, "someStringField");
}
}
Related
I am trying to write unit test cases for one of the methods in code.Below is the method
public boolean isValid() {
if(object == null)
return false
//do something here and return value.
}
The object is created by this method which is done before without getter setter method.
private Object returnObject() {
object = Axis2ConfigurationContextFactory.getConfigurationContext();
return object;
}
When I try to test isValid(), the object is always null, so it never goes in the code to do something.
I was checking if there is any way to skip that line or make the object not null. I also tried creating an object using returnObject method. But it uses Axis library classes which throws error if it does not find certain data. What can be done in this case? I am dealing with legacy code so any pointers would be helpful.
Edit : Adding test implementation.
#PowerMockIgnore({ "javax.xml.*", "org.w3c.dom.*", "javax.management.*" })
public class ClassTest {
private ClassTest classTestObj;
#BeforeMethod
public void callClassConstructor() {
classTestObj = //call class constructor
}
#BeforeClass
public void setUpClass() throws Exception {
MockitoAnnotations.initMocks(this);
}
#Test
public boolean isValidTest() {
Boolean result = classTestObj.isValid();
Assert.assertEquals(result);
}
}
As I mentioned in the before comment, you can make use of MockedStatic to mock the static method - https://javadoc.io/static/org.mockito/mockito-core/4.4.0/org/mockito/Mockito.html#static_mocks
So your code will somewhat look like the below one if you are making use of Mockito instead of PowerMockito.
#RunWith(MockitoJUnitRunner.class)
public class ClassTest
{
#Mock
private Object mockAxis2ConfigurationContextFactoryObject;
#Test
public boolean isValidTest() {
try (MockedStatic<Axis2ConfigurationContextFactory> mockedStatic = mockStatic(Axis2ConfigurationContextFactory.class)) {
mockedStatic.when(()->Axis2ConfigurationContextFactory.getConfigurationContext()).thenReturn(mockAxis2ConfigurationContextFactoryObject);
Boolean result = classTestObj.isValid();
Assert.assertEquals(result);
}
}
I have a public static method which internally uses another static but private method. SonarQube bothers me to test this private method. How can I do this using Mockito (inline)?
public class MyClass {
public static boolean isXxxValid(String value1, String value2) {
try {
var s = myPrivateMethod(anyString);
...
} catch (Exception ex) {
...
}
}
private static String myPrivateMethod(final String input) {
...
}
}
How can I test or mock myPrivateMethod()?
In general the testing of private methods should be done via the business interface (the public methods of your class).
But since you are mentioning powermock I guess your idea is to mock that privat method to test your public method. That would be another anti pattern. You should never mock parts of the class under test.
In your case it seem that you need to mock the external dependencies that are used in your private method.
My class structure is as follows:
public class MyParentClass {
void doSomethingParent() {
System.out.println("something in parent");
}
}
public class MyClass extends MyParentClass {
protected String createDummyRequest(Holder myHolder) {
//...
super.doSomethingParent();//I want to avoid this
//...
callingDB();
return "processedOutput";
}
private void callingDB() {
System.out.println("Calling to DB");
}
}
Then my unit test:
public class UnitTest {
public void testCreateDummyRequest() {
//create my mock holder
Holder mockHolder = new Holder();
MyClass mockObj = Mockito.mock(MyClass.class);
//mock doSomethingParent()
//mock callingDB()
//as mockObj is a fully mock, but I need to run my real method
//Mockito.when(mockObj.createDummyRequest(mockHolder)).thenCallRealMethod();
mockObj.createDummyRequest(mockHolder);
//Problem: doSomethingParent() is getting called though I have mocked it
}
}
How do I prevent the calling of the super.doSomethingParent() in my method? (method which I am writing my test)
With this class structure mocking and testing is real hard. If possible, I'd advice to change the structure as in mist cases a class structure that's hard to mock and test is equally hard to extend and maintain.
So if you could change your class structure to something similar to:
public class MyClass {
private DoSomethingProvider doSomethingProvider;
private DbConnector dbConnector;
public MyClass (DoSomethingProvider p, DbConnector c) {
doSomethingProvicer = p;
dbConnector = c;
}
protected String createDummyRequest(Holder myHolder){
//...
doSomethingProvider.doSomethingParent();
//...
dbConnector.callingDB();
return "processedOutput";
}
}
Then you could easily create your instance with mocks of DoSomethingProvider and DbConnector and voila....
If you can't change your class structure you need to use Mockito.spy instead of Mockito.mock to stub specific method calls but use the real object.
public void testCreateDummyRequest(){
//create my mock holder
Holder mockHolder = new Holder();
MyClass mockObj = Mockito.spy(new MyClass());
Mockito.doNothing().when(mockObj).doSomething();
mockObj.createDummyRequest(mockHolder);
}
Note: Using the super keyword prevents Mockito from stubbing that method call. I don't know if there is a way to stub calls to super. If possible (as in you didn't override the parent method in your class), just ommit the keyword.
I faced similar issue, so I find out that using spy() can hepld.
public class UnitTest {
private MyClass myObj;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
myObj= spy(new MyClass());
}
#Test
public void mockedSuperClassMethod(){
doNothing().when((MyParentClass )myObj).doSomethingParent();
//...
}
}
This approach works for me.
I found another approach, which turned out to be very useful in my case.
In the case I had, I needed to create a new class extending another, which included a very complex (legacy code) protected final method. Due to the complexity, it wasn't really possible to refactor to use composition, so here's what I came up with.
Let's say I have the following:
abstract class Parent {
public abstract void implementMe();
protected final void doComplexStuff( /* a long parameter list */) {
// very complex legacy logic
}
}
class MyNewClass extends Parent {
#Override
public void implementMe() {
// custom stuff
doComplexStuff(/* a long parameter list */); // calling the parent
// some more custom stuff
}
}
Here's how I rearranged this code:
abstract class Parent {
public abstract void implementMe();
protected final void doComplexStuff( /* a long parameter list */) {
// very complex legacy logic
}
}
interface ComplexStuffExecutor {
void executeComplexStuff(/* a long parameter list, matching the one from doComplexStuff */);
}
class MyNewClass extends Parent {
private final ComplexStuffExecutor complexStuffExecutor;
MyNewClass() {
this.complexStuffExecutor = this::doComplexStuff;
}
MyNewClass(ComplexStuffExecutor complexStuffExecutor) {
this.complexStuffExecutor = complexStuffExecutor;
}
#Override
public void implementMe() {
// custom stuff
complexStuffExecutor.doComplexStuff(/* a long parameter list */); // either calling the parent or the injected ComplexStuffExecutor
// some more custom stuff
}
}
When creating instance of MyNewClass for "production" purposes, I can use the default constructor.
When writing unit tests, however, I'd use the constructor, where I can inject ComplexStuffExecutor, provide a mock there and only test my custom logic from MyNewClass, i.e.:
class MyNewClassTest {
#Test
void testImplementMe() {
ComplexStuffExecutor complexStuffExecutor = Mockito.mock(ComplexStuffExecutor.class);
doNothing().when(complexStuffExecutor).executeComplexStuff(/* expected parameters */);
MyNewClass systemUnderTest = new MyNewClass(complexStuffExecutor);
// perform tests
}
}
At first glance, it seems like adding some boilerplate code just to make the code testable. However, I can also see it as an indicator of how the code should actually look like. Perhaps one day someone (who would find courage and budget ;) ) could refactor the code e.g. to implement the ComplexStuffExecutor with the logic from doComplexStuff from Parent, inject it into MyNewClass and get rid of inheritance.
Here is how it can be done
public class BaseController {
public void method() {
validate(); // I don't want to run this!
}
}
public class JDrivenController extends BaseController {
public void method(){
super.method()
load(); // I only want to test this!
}
}
#Test
public void testSave() {
JDrivenController spy = Mockito.spy(new JDrivenController());
// Prevent/stub logic in super.method()
Mockito.doNothing().when((BaseController)spy).validate();
// When
spy.method();
// Then
verify(spy).load();
}
Source: https://blog.jdriven.com/2013/05/mock-superclass-method-with-mockito/
I am recently working on TDD with JUnit and Mockito. For some purpose within a method, I am using an Util class (an utility class having methods in project context). The thing is what I am facing is how to mock such classes in Mockito. I am not able to find as such implementation regarding static methods in Mockito. Some suggest using PowerMock on top of Mockito but wouldn't that replace my JunitMockitoRunner?
The way I am using the static function is:
public void doSomething(int x){
//Some code
Y y = Util.someStaticMethod(x);
//Some more code
}
EDIT : Also I read somewhere that using static methods is a code smell and is a sign of bad design. So how should I be refactoring the design and what advantages will I be having as a result?
How should I be refactoring the design and what advantages will I be having as a result?
Well, if you need to mock the static utility method, then make it an instance method of an injectable object, so that you can inject a mock implementation of this object. The advantage is that it makes your code more testable:
public class Util {
public Y someInstanceMethod(X x) {
...
}
}
public class ClassToBeTested {
private Util util;
public ClassToBeTested(Util util) {
this.util = util;
}
public void doSomething(int x){
//Some code
Y y = util.someInstanceMethod(x);
//Some more code
}
}
public class ClassToBeTestedTest {
public void testDoSomething() {
Util mockUtil = mock(Util.class);
ClassToBeTested t = new ClassToBeTested(mockUtil);
when(mockUtil.someInstanceMethd(3)).thenReturn(...);
...
}
}
That's the main selling point of dependency injection: it makes your code testable.
I do something like that for mocking static Util classes with jMockit.
public class UtilsTest {
#After
public void teardown() {
Mockit.restoreAllOriginalDefinitions();
}
#Test
public void testMyUtil() {
Mockit.setUpMocks( MockUtil.class );
}
}
#MockClass(realClass=Util.class)
public class MockUtil{
#Mock
public static MySpecialClass someStaticMethod(int x) {
return Mockito.mock(MySpecialClass.class);
}
}
I want to write a test case that will verify a method in my class.
I have a local ApplicationLauncher object in my method that has to be mocked because it calls a method, launch(), which should not be called in a unit test.
public class RunApp
{
public void check(String name)
{
if(name !=null)
{
ApplicationLauncher launcher = Application.getLauncher("launch");
String appName = name+".bat";
launcher.launch(appName);
}
}
}
My JUnit test code is below:
RunApp runapp = new RunApp();
#Mock
ApplicationLauncher launcher;
#Test
public void test()
{
runapp.check("test");
verify(launcher,atLeastOnce).launch(anyString());
}
I am not able to return a mock object like
when(Application.getLauncher(anyString())).thenReturn(launcher);
since getLauncher is a static method in Application class. How can I solve this?
A better application design might be to have ApplicationLauncher as an interface and create production and test implementations (or just mock the test implementation). You would need to pass an instance of ApplicationLauncher into your RunApp class, perhaps in the constructor.
You can mock static methods using PowerMock, however you should check whether the static method call is really necessary.
You could refactor your class to accept the launcher to be "injected".
public class RunApp
{
public void check(String name)
{
check(name, Application.getLauncher("launch"));
}
protected check(String name, ApplicationLauncher launcher) {
if (name != null)
{
String appName = name + ".bat";
launcher.launch(appName);
}
}
}
That way you could use the new package-protected check() method to test your code using a fake launcher.