I am new to Junit,Below is the junit code which i am running.
package com.de.base.util.general;
import static org.junit.Assert.*;
import static org.mockito.Mockito.when;
import java.util.HashMap;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.powermock.api.mockito.PowerMockito;
@RunWith(MockitoJUnitRunner.class)
public class JReportUtilTest {
@InjectMocks
ReportUtil w_res = new ReportUtil();
@Mock
CollectionUtil w_util;
@Test
public void test_removeHashedSettings() throws Exception {
HashMap<String ,String> w_abc = new HashMap<String,String>();
w_abc.put("abc","89");
//CollectionUtil mock = org.mockito.Mockito.mock(CollectionUtil.class);
//PowerMockito.mockStatic(CollectionUtil.class,w_abc);
when(w_util.createHashMap("abc:89", ":")).thenReturn(w_abc);
assertEquals("abc:89:",ReportUtil.removeHashedSettings("1", "abc:89", ":"));
}
}
Here is my api removedHashedSettingsin ReportUtil
public static String removeHashedSettings(String key, String a_settings, String deilimiter) throws Exception
{
if (!(key != null && key.trim().length() > 0))
return a_settings;
if (!(a_settings != null && a_settings.trim().length() > 0))
return a_settings;
HashMap hSettings = CollectionUtil.createHashMap(a_settings, deilimiter);
hSettings.remove(key);
return getSettingFromHash(hSettings, deilimiter);
}
Below is the code for createHashMap in CollectionUtil which i have to mock.
public static HashMap<String, String> createHashMap(String a_NameValStr, String a_Delim)// throws Exception
{
HashMap<String, String> w_KeyVal = new HashMap<String, String>();
if (LOGGER.isInfoEnabled()) LOGGER.info("CollectionUtil:createHashMap:Hashing string: "+ a_NameValStr );
if(a_NameValStr == null) return w_KeyVal;
StringTokenizer w_StrTkn = new StringTokenizer(a_NameValStr, a_Delim);
if( w_StrTkn.countTokens() == 0 || (w_StrTkn.countTokens()%2) != 0 )
{
LOGGER.warn("CollectionUtil:createHashMap:Invalid number of tokens to hash: "+ a_NameValStr+":"+w_StrTkn.countTokens() );
return w_KeyVal;
}
while (w_StrTkn.hasMoreTokens()) w_KeyVal.put( w_StrTkn.nextToken(), w_StrTkn.nextToken());
System.out.println(w_KeyVal);
return w_KeyVal;
}
Here is the error i am getting while running my junit test case.
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);
Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
Those methods *cannot* be stubbed/verified.
Mocking methods declared on non-public parent classes is not supported.
2. inside when() you don't call method on mock but on some other object.
at com.de.base.util.general.JReportUtilTest.test_removeHashedSettings(JReportUtilTest.java:32)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37)
at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
I am using mockito -all-1.10.19.jar,powermock-api-mockito-1.6.6.jar,powermock-core-1.6.6.jar,powermock-module-junit4-1.6.6.jar Can anyone help me to solve this problem?
You don't use the PowerMock runner :
Mockito cannot mock static method but PowerMock does.
And you should mock the class with static method :
Anyway a better design is replacing the static method by an instance method.
Static methods are not naturally testable and force to create complex and not readable workaround.
For example, look at the complexity of the mix of dependencies required to test a simple class.
You should keep the use of static methods as helper that don't perform core logic of the domain and that don't need to be mocked.
When the methods perform core logic of the domain as it is the case for the
createHashMap() static method
, you very probably need to mock it to not create side effects between dependent classes during the tests.And as you have noticed : mocking static methods is really clumsy as static methods are really not designed to be overriden.
Besides, for core logic of the domain, you should have the ability to take advantage of the OOP (inheritancy, polymorphism, design patterns, etc... ), how to achieve it with static methods ? –
For legacy code we cannot really not change, it is acceptable but otherwise, no it doesn't and you should refactor your code.
Here is my working code:
and the TestHarnes class