I have a class with code similar to :
public class class1{
private static final ConfigurationService config = Util.getInstance(ConfigurationService.class);
private SendQueueMessages sender;
public void start() throws LifecycleException{
LOGGER.info("Starting");
final ActiveMq activemq = config.getConfiguration().getActiveMq();
sender = new SendQueueMessages(activemq.getQueueName());
}
}
Elsewhere in the program Guice is being used to bind the configuration service and Util like so:
Util.register(new ThingICantChange(){
#Override
protected void configure (){
super.configure();
bind(ConfigurationService.class).to(ConfigurationServiceImpl.class).asEagerSingleton();
}
});
Is this possible to unit test? I was initially trying to use JUnit 5 and mockito, but it became apparent that I needed to mock static classes/methods (IoCUtils) and switched to JUnit4 for PowerMock.
I have tried:
#RunWith(PowerMockRunner.class)
#PrepareForTest(Util.class)
public class Class1Test{
#Test
public void canStart(){
mockStatic(Util.class);
when(Util.getInstance(ConfigurationService.class)).thenReturn(new ConfigurationService);
Class1 class = new Class1();
class.start();
//etc.
}
}
However this just gives me an error about Util not prepared for test. Changing mockStatic() to PowerMockito.spy() did get me to the when, but then throws a null pointer error.
I found a solution, though I have mixed feelings about it.
Using the Util.register (the 2nd code block) I registered a configuration service implementation that created the mock objects. This worked and let me test the start() method, but feels kind of against the idea of a unit test.
public class ConfigServiceTest implements ConfigurationService{
#Override
public Configuration getConfiguration() {
Configuration conf = mock(Configuration.class);
ActiveMq amq = mock(ActiveMq.class);
when(amq.getQueueName()).thenReturn("test");
when(amq.getBrokerUrl()).thenReturn("http://127.0.0.1:61616?soTimeout=1000");
when(conf.getActiveMq()).thenReturn(amq);
return conf;
}
//other methods just allowed to return null
}
Then in the test:
Util.register(new thingICantChange(){
#Override
protected void configure (){
super.configure();
bind(ConfigurationService.class).to(ConfigServiceTest.class).asEagerSingleton();
}
});
class1 service = new class1();
service.start();
Assert.assertEquals(true, true);
start is void and not int a new thread so Assert.assertEquals(true,true) is the best anyone around me knew to check that start ran. Mockito/PowerMock times(1) would require a mock of class1 which seems rather counter to a unit test to see IF it can run.
Related
Even though I have read the manual and gone through multiple answers for Powermock, could not mock a static method for my use case.
Class:
#Component
public class SCUtil{
public void createSC(){
try {
String host = InetAddress.getLocalHost().getHostAddress();
// ...
// ...
// ...
} catch (UnknownHostException e) {
log.error("Exception in creasting SC");
throw new ServiceException(e);
}
}
}
Test class:
#RunWith(PowerMockRunner.class)
#PrepareForTest( InetAddress.class )
public class SCUtilTest {
#InjectMocks
private SCUtil scUtil;
private Event event;
#Before
public void beforeEveryTest () {
event = new InterventionEvent();
}
#Test(expected = ServiceException.class)
public void testCreateSC_Exception () {
PowerMockito.mockStatic(InetAddress.class);
PowerMockito.when(InetAddress.getLocalHost()).thenThrow(new UnknownHostException("test"));
scUtil.createSC(event);
}
}
Here, the test is failing as no exception is being thrown:
java.lang.AssertionError: Expected exception:
com.example.v1.test.selftest.errorhandling.ServiceException
I have wrecked more than a couple of hours in this and still have not gotten it to work. What am I doing wrong?
Thank you for all the help in advance :)
java.net.InetAddress is a system class. The caller of the system class should be defined in #PrepareForTest({ClassThatCallsTheSystemClass.class}).
See documentation.
The way to go about mocking system classes are a bit different than
usual though. Normally you would prepare the class that contains the
static methods (let's call it X) you like to mock but because it's
impossible for PowerMock to prepare a system class for testing so
another approach has to be taken. So instead of preparing X you
prepare the class that calls the static methods in X!
Please note #InjectMocks annotation does not inject static mocks, it can be removed.
Example of working test:
#RunWith(PowerMockRunner.class)
#PrepareForTest(SCUtil.class)
public class SCUtilTest {
private SCUtil scUtil = new SCUtil();
#Test(expected = ServiceException.class)
public void testCreateSC_Exception () throws UnknownHostException {
PowerMockito.mockStatic(InetAddress.class);
PowerMockito.when(InetAddress.getLocalHost()).thenThrow(new UnknownHostException("test"));
scUtil.createSC();
}
}
I am using Junit 4.12 with PowerMock 1.6 with Mockito. I have also used PowerMockRule library as described here. I am trying to execute initialization code for all of my test cases exactly once as described in this SO Thread. Its executing the initialization code exactly one time however, if I do ServiceInitializer.INSTANCE inside test method it returns me new object. I am not able to understand this behavior. Does anyone have any idea why this is happening? If I execute my code without PowerMockRule Library and run my test with PowerMockRunner then it works fine but in that case my ClassRule is not getting executed.
public class ServiceInitializer extends ExternalResource {
public static final TestRule INSTANCE = new ServiceInitializer();
private final AtomicBoolean started = new AtomicBoolean();
#Override protected void before() throws Throwable {
if (!started.compareAndSet(false, true)) {
return;
}
// Initialization code goes here
System.out.println("ServiceInitializationHelper:"+this); //Print Address #3702c2f1
}
#Override protected void after() {
}
}
class BaseTest{
#Rule
public PowerMockRule powerMockRule = new PowerMockRule();
#ClassRule
public static final TestRule serviceInitializer = ServiceInitializer.INSTANCE;
#Before
public final void preTest() {
// some code
}
#After
public final void postTest() {
//some code
}
}
#PrepareForTest({MyClass.class})
public class MyTest extends BaseTest {
#Test
public void testMethodA_1(){
System.out.println(ServiceInitializer.INSTANCE);//Print Address #54d41c2b
}
}
Update
I printed the classloader for the classes and it turns out for first print statement the classloder was sun.misc.Launcher$AppClassLoader and for the second print statement the classloder was org.powermock.core.classloader.MockClassLoader. How can I solve this?
You don't have a singleton. You have a static INSTANCE variable. Keep in mind that one of those can exist for every classloader you have.
Instead make an enum of ServiceInitializer, like so
public enum ServiceInitializer {
INSTANCE;
// rest of class goes here
}
And rely on the JVM's language contracts to ensure the singleton.
Or, better yet, write your code to handle situations where more than one ServiceInitializer can exist, but it just happens that your program only uses one instance. This is the ideal choice, allowing you to alternate between the real ServiceInitializer and a mock if desired.
Edwin is correct; this is an issue with PowerMock creating a new ClassLoader for every test. I strongly recommend refactoring your code so it can be tested without PoeerMock and switch to Mockito.
These books may be helpful
Working Effectively With Legacy Code
Refactoring to Patterns
In the mean time, you can reference ServiceInitializer from your base class:
public class ServiceInitializer extends ExternalResource {
public static final ServiceInitializer INSTANCE = new ServiceInitializer();
private final AtomicBoolean started = new AtomicBoolean();
#Override protected void before() throws Throwable {
if (!started.compareAndSet(false, true)) {
return;
}
// Initialization code goes here
System.out.println("ServiceInitializationHelper:"+this);
}
#Override protected void after() {
}
}
class BaseTest{
#Rule
public PowerMockRule powerMockRule = new PowerMockRule();
#ClassRule
public static final ServiceInitializer serviceInitializer = ServiceInitializer.INSTANCE;
#Before
public final void preTest() {
// some code
}
#After
public final void postTest() {
//some code
}
}
#PrepareForTest({MyClass.class})
public class MyTest extends BaseTest {
#Test
public void testMethodA_1(){
System.out.println(serviceInitializer);
}
}
Well I finally found the work around for this problem. As explained in my question my class was getting loaded by two different class loaders and thus causing problems for me. In order to resolve my issue I used #PowerMockIgnore annotation in order to defer its loading as follows:
#PowerMockIgnore({"com.mypackage.*"})
class BaseTest{
// Stuff goes here
}
This annotation tells PowerMock to defer the loading of classes with the names supplied to value() to the system classloader. You can read about this annotation from here.
I have a helper class which contains an public static method getProductHandler(String name):
public class ProductHandlerManager {
public static Handler getProductHandler(String name) {
Handler handler = findProductHandler(name);
return handler;
}
}
A CustomerService class uses the above ProductHandlerManager:
public class CustomerService {
...
public void handleProduct() {
Handler appleHandler = ProductHandlerManager.getProductHandler("apple");
appleHandler.post(new Runnable() {
#Override
public void run() {
//...
}
});
}
}
I want to unit test handleProduct() method in CustomerService class. I tried using mockito to mock the ProductManager.getProductHandler("apple") part in test, however, mockito doesn't support static method mocking. How can I use Mockito to unit test handleProduct() function then?
Please don't suggest me to use Powermock, since I read some article which says if I need to mock static method, it indicates a bad design. But I can accept suggestions about code refactoring to make it testable.
You can refactor and specify a Handler yourself. These can often be package private, if you put your tests in the same package as your classes-under-test—even if they're in a different source folder (e.g. src vs testsrc). Guava (Google Commons) has a handy #VisibleForTesting documentation annotation, too, though Javadoc tends to work as well.
public class CustomerService {
public void handleProduct() {
handle(ProductHandlerManager.getProductHandler("apple"));
}
/** Visible for testing. */
void handleProduct(Handler handler) {
handler.post(new Runnable() {
#Override
public void run() {
//...
}
});
}
}
At this point, you can test handleProduct(Handler) intensively as a unit test, then only test handleProduct() as an integration test to ensure the "apple" product handler interacts correctly.
I am facing problem with testing class which has implemented some local connection to EJB in the constructor. This connection is used just inside the constructor and sets some private attributes of the instantiated class.
MyClass which I want to test:
public class MyClass {
private String myValue;
public MyClass() throws Exception {
MyBeanLocal local = EJBFactory.getLocal(MyBeanLocal.class);
myValue = local.fetchValue();
}
public void processValue() {
... do some String magic which should be tested ...
}
public String getValue() {
return myValue;
}
}
EJBFactory contains some enhanced lookup (with caching) and can return local or remote connection (remote requires server location).
MyBeanLocal interface
public interface MyLocalBean {
public String fetchValue();
}
And finally my junit class where I want to test MyClass.processValue method:
public class MyClassTest {
private MyClass myClass;
#Before
public void setUp() {
myClass = new MyClass();
}
#Test
public void testProcessValue() {
Assert.assertEquals(myClass.processValue(), "MY EXPECTED VALUE");
}
}
The question is how to test situation when I run JUnits in local machine (or some automatic test machine like Hudson or Jenkins) and bean runs on application server context which is different than my local one. I can't touch to production code, just need to write test.
Actually I don't need to make MyBeanLocal functional, but I need myValue set.
I was thinking about mocking, but I am not familiar with that.
You can use the JMockit mocking API (which I created) for such tests:
public class MyClassTest
{
#Tested MyClass myClass;
#Test
public void processValue() {
new NonStrictExpectations() {
#Mocked EJBFactory fac;
#Mocked MyBeanLocal mb;
{
EJBFactory.getLocal(MyBeanLocal.class); result = mb;
mb.fetchValue(); result = "SOME VALUE";
}
};
assertEquals(myClass.processValue(), "MY EXPECTED VALUE");
}
}
The mocking of EJBFactory may even be omitted, if it still returns an object in the unit testing environment.
When testing classes that involve database connections mocking is usually the best way to go.
There are several frameworks that make mocking objects a lot easier, one of which is Mockito.
You can find more info about it here
Martin Fowler also wrote a good article about when to use mocks and what the difference is between a mock and a stub. Here's a link to the article.
Is it possible to mock a class object using Mockito and/or PowerMockito?
Something like:
Class<Runnable> mockRunnableClass = mock(Class<Runnable>.class);
An alternative to mocking Class might be to use a Factory instead. I know you are concerned about refactoring, but this could be done without changing the public API of the class. You haven't provided much code to understand the class you are trying to test, but here's an example of refactoring without changing the API. It's a trivial class, but it might give you an idea.
public class Instantiator {
public Runnable getNewInstance(Class<Runnable> runnableClass) throws Exception {
return runnableClass.newInstance();
}
}
Of course, the easiest thing to do to test this trivial class would be to use a genuine Runnable class, but if you tried to mock the Class, you would run into the problems you're having. So, you could refactor it thus:
public class PassThruFactory {
public Object newInstance(Class<?> clazz) throws Exception {
return clazz.newInstance();
}
}
public class Instantiator {
private PassThruFactory factory = new PassThruFactory();
public Runnable getNewInstance(Class<Runnable> runnableClass) throws Exception {
return (Runnable)factory.newInstance(runnableClass);
}
}
Now Instantiator does exactly the (trivially simple) thing it was doing before with the same public API and no need for any client of the class to do any special injecting of their own. However, if you wanted to mock the factory class and inject it, that's very easy to do.
why not using an agent if you can't refactor the code there isn't many options, as #jherics mentionned, java system classes are loaded by the bootstrap classloader and powermock can't redefine their bytecode.
However Powermock now coms with an agent, that will allow system classes mock. Check here for complete explanation.
The main idea is to modify your java command and add :
-javaagent: path/to/powermock-module-javaagent-1.4.12.jar
The basic thing this agent is doing is to definalize classes, to allow future mocking in a specific test, that's why you'll need to use specific types to communicate with the agent, for example with JUnit :
#Rule PowerMockRule rule = new PowerMockRule(); // found in the junit4 rule agent jar
TestNG is also supported. Just check the wiki page for more information.
Hope that helps.
First, as stated in the comments, you would need to do:
Class<Runnable> mockRunnableaClass = (Class<Runnable>)mock(Class.class);
But that won't work in the usual way because of a limitation with PowerMock. You cannot simply mock classes in from java.lang, java.net, java.io or other system classes because they're loaded by Java's bootstrap classloader and cannot be byte-code manipulated by PowerMock's classloader. (See PowerMock FAQ #4.) As of PowerMock 1.2.5, you can work around this. If the class you wanted to test was this:
public class ClassToTest {
private Class<Runnable> runnableClass;
public void setRunnableClass(Class<Runnable> runnableClass) {
this.runnableClass = runnableClass;
}
public Runnable foo() {
return runnableClass.newInstance();
}
}
Then you would do this:
#RunWith(PowerMockRunner.class)
#PrepareForTest({ ClassToTest.class }) // Prepare the calling class for test
public class SystemClassUserTest {
#Test
public void testFoo() throws Exception {
Class<Runnable> mockClass = (Class<Runnable>) mock(Class.class);
Runnable mockRunnable = mock(Runnable.class);
ClassToTest objectUT = new ClassToTest();
objectUT.setRunnableClass(mockClass);
when(mockClass.newInstance()).thenReturn(mockRunnable);
assertThat(objectUT.foo(), is(sameInstance(mockRunnable);
}
}
How about this. creating a get method of the has a Object (MS) in class PCService and then mock it.
public class PCService implements PCServiceIf {
public MSIf getMS() {
return ms;
}
private MSIf ms = new MS();
public boolean isMovieAccessibleToMyLevel(String myLevel, String movieId) {
return getMS().getPCL(movieId);
}
}
#Test
public void testIsMovieAccessibleToMyLevelMock() {
msMock = mock(MS.class);
spy = spy(new PCService());
doReturn(msMock).when(spy).getMS();
when(msMock.getPCL(movieId)).thenReturn(value);
when(spy.getMS().getPCL(movieId)).thenReturn(value);
assertTrue(spy.isMovieAccessibleToMyLevel("PG", movieId) == true);
}