Working with PowerMock

Sometimes, we cannot unit test our code, as the special Java constructs hide the testing impediments (a LAN connection or database connection in a private method, final method, static method, or initialization block), such as private methods, final methods and classes, static methods and initialization blocks, new operator, and so on. We refactor code for testability (explained in the Designing for testability with Mockito section) and, sometimes, compromise a good design for the sole purpose of testability. For example, final classes and methods are avoided, private methods are converted to protected or default, or unnecessarily moved to a collaborator class, static methods are avoided completely, and so on. This is done simply because of the limitations of the existing frameworks. Also, these aren't just feature limitations; they are intentional choices. Mockito could do the things PowerMock does, but it doesn't because those are test smells and strong indications that you are following a poor design. Many of these are bad designs by themselves even outside testability and/or things you shouldn't do even in the name of testability. For example, the static method involves direct coupling between random chunks of code, directly subverting good OO design and encapsulation.

Converting private methods to protected ones so that you can stub internal methods is not a good testing design. Partial mocks are typically code smell against the SRP, and refactoring such things into another class makes for a better design!

Code with final methods typically protects a specific implementation, and that should imply that such implementations have an interface that can be stubbed instead.

Some design decisions taken without the pressure of the testability result with little thought for it (static/final/no SRP), and this results in code that is actively difficult to test. These are not things people should be doing intentionally, and then use PowerMock as a matter of recourse. PowerMock is a fallback for legacy code that they should aim to stop using with time.

PowerMock provides special mocking capabilities and allows us to unit test code even when the special Java constructs hide the testing impediments. PowerMock is a framework that extends other mock libraries, such as EasyMock and Mockito, with more powerful capabilities. PowerMock uses a custom classloader and bytecode manipulation to enable mocking of static methods, constructors, final classes and methods, private methods, removal of static initializers, and so on. PowerMock is essential for legacy code.

Note

The following is the website for PowerMock:

www.powermock.org

PowerMock's distribution for EasyMock and Mockito can be downloaded from the following website:

URL:https://code.google.com/p/powermock/wiki/Downloads?tm=2

Download the powermock-mockito-junit-1.5.5.zip file for Mockito and JUnit. The ZIP file contains the powermock-mockito-1.5.5-full.jar file and its dependencies.

The following examples explore the Mockito extension API, also known as PowerMockito.

You need to annotate the test class with the @RunWith(PowerMockRunner.class) annotation in order to bootstrap PowerMock. The classes that cannot be mocked need to be prepared for testability by using the @PrepareForTest annotation.

We'll create a Java project to unit test the PowerMockito capabilities. The following are the steps to set up the project:

  1. Create a Java project named UnitTestingLegacyCode.
  2. Extract the powermock-mockito-junit-1.5.5.zip file, copy the JAR files, and add to the project's classpath.
  3. Create two source folders, namely, src and test, and add the com.packt.legacy.powermockito packages to them. The following figure displays the project structure:
    Working with PowerMock

We'll examine the mocking capabilities of PowerMockito for untestable constructs, such as private method, static method, initialization blocks, final classes and methods, and constructor and super constructor.

Note

You can get more information from the following URL:

https://code.google.com/p/powermock/wiki/SuppressUnwantedBehavior

Stubbing static methods

This section deals with static methods. You cannot stub a static method with Mockito, but PowerMockito allows us to stub static methods. The following MedicalBill class generates the medical bill ID; the generateId() method is a static method and, in real life, it calls the database to generate an identifier. For simplicity, we will call the random number generator to generate an integer:

package com.packt.legacy.powermockito;

import java.util.Random;

public class MedicalBill {

  public static int generateId(){
    return new Random().nextInt();
  }
}

You cannot stub the generateId() method to return a hardcoded value, but the following mockStatic()method of PowerMockito allows us to stub the generateId() method to return a hardcoded value:

package com.packt.legacy.powermockito;

import static org.junit.Assert.assertEquals;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import static org.powermock.api.mockito.PowerMockito.when;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest(MedicalBill.class)
public class StaticMethodTest {

  @Test
  public void stubs_static_methods() throws Exception {
    System.out.println(MedicalBill.generateId());
    //enable mocking
    mockStatic(MedicalBill.class);
    //stub the static method
    PowerMockito.when(MedicalBill.generateId()).thenReturn(1);
    //check the stubbed value
    assertEquals(1, MedicalBill.generateId());
  }
}

The test class is annotated with @RunWith(PowerMockRunner.class) and @PrepareForTest(MedicalBill.class), where PowerMockRunner bootstraps PowerMockito to use a classloader to load the classes, and @PrepareForTest enables the classes to be mocked.

The static mockStatic() method is defined in the org.powermock.api.mockito. PowerMockito class. This method allows us to mock static methods.

We need to mock static methods in the following circumstances:

  • Code under test calls a utility class or a data access object with static methods, and static methods hide testing impediments, such as a database call, file access, and so on
  • Code under test calls a third-party library; we cannot modify the third-party library source code, which in turn hides a testing impediment in a static method

Suppressing static blocks

Suppose legacy code has a static data initialization block and it loads a database driver in this block. If you need to unit test the class, you need to load the class and in turn, the static block is processed. So your test will indirectly load the database driver before executing a test. This is unacceptable, but you cannot suppress the static initialization using any mocking tool. PowerMockito allows us to suppress the static blocks and enables us to write test for the code that hides testing impediments in static initialization blocks.

The following class has a static block whereby it initializes a value with 100/0. This 100/0 signifies a testing impediment. If you load the class in a test harness, the test will fail with a divide by zero exception. Division by zero is just a trick to show the effect of the PowerMock @Suppress annotation and to state that the class does not work in functional mode:

public class StaticInitializationBlock {
  static int value;
  static{
    value = 100/0;
    System.out.println("In static block");
  }
}

The following PowerMockito test suppresses the static block:

package com.packt.legacy.powermockito;

import static org.junit.Assert.assertEquals;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@SuppressStaticInitializationFor("com.packt.legacy.powermockito.StaticInitializationBlock")
public class StaticInitializationBlockTest {

  @Test
  public void supresses_static_initialization_blocks() {
    assertEquals(0,StaticInitializationBlock.value);
  }
}

In the preceding test, we assert StaticInitializationBlock.value against 0 because 0 is the default value for an integer. The @SuppressStaticInitializationFor annotation instructs the PowerMockito classloader to skip the static initialization for the fully qualified class name.

Suppressing a superclass constructor

When a class needs to extend from another class in a third-party framework or some other kind of module and the third-party class constructor hides a testing impediment, then that prevents you from unit testing your own code. For example, the framework may try to connect to the Internet to load some value or access filesystem for some reason. You cannot suppress the super constructor chaining from your unit test, and hence, your test may fail.

The following class has a constructor that hides a testing impediment; the divide by zero replicates a testing impediment:

class DontExtendMePlease{
  DontExtendMePlease(){
    int x =1/0;
  }
}

The following class extends the DontExtendMePlease class:

public class SuppressSuperConstructor extends DontExtendMePlease{

  public SuppressSuperConstructor() {
    super();
  }

}

When we instantiate the SuppressSuperConstructor class in a test case, the test fails with the following error, to indicate that you cannot instantiate the class, as the super class constructor has some problem:

Suppressing a superclass constructor

The PowerMockito JUnit test resolves the issue by suppressing the super class constructor:

import static org.powermock.api.support.membermodification.MemberMatcher.constructor;
import static org.powermock.api.support.membermodification.MemberModifier.suppress;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest(SuppressSuperConstructor.class)
public class SuppressSuperConstructorTest {

  @Test
  public void supresses_super_class_constructor() {
    suppress(constructor(DontExtendMePlease.class));
    new SuppressSuperConstructor();
    assertTrue("Just checking", true);
  }
}

The suppress method takes a constructor or a field or a method. We are creating a constructor of the DontExtendMePlease class using the constructor (class) method. The PowerMockito classloader suppresses the constructor and allows us to unit test the code.

Suppressing our own constructor

Just like with the super class constructor, when we add our own constructor that hides a testing impediment, we cannot instantiate the class in test harness and hence, cannot unit test the class.

The following constructor divides by zero and indicates a testing impediment:

public class SuppressConstructor {

  public int someValue = 100;
  public SuppressConstructor(int val){
    val = val/0;
  }

}

However, PowerMock provides us a Whitebox class. It allows us to create class instances by suppressing the defined constructors; but the problem is that the values we initialize in the constructor are just ignored, or rather, not initialized. The following JUnit test uses Whitebox to suppress the parameterized constructor:

import static org.junit.Assert.assertNotNull;
import org.junit.Test;
import org.powermock.reflect.Whitebox;

public class SuppressConstructorTest {

  @Test
  public void supresses_own_constructor() throws Exception {
    SuppressConstructor nasty = Whitebox.newInstance(SuppressConstructor.class);
    assertNotNull(nasty);
  }
}

Suppressing methods

Sometimes, we need to suppress method calls. For instance, when our code under the test calls another method that hides a testing impediment, we must suppress the second method to proceed with the testing. Suppressing means the method will not be invoked; if a method returns a string (or any object) value, then a null value will be returned.

The following class has a private getCurrency()method; this method is called from the format() method:

package com.packt.legacy.powermockito;

public class SuppressMethod {

  public String format(String str){
    return str + getCurrency();
  }

  private String getCurrency(){
    return "$";
  }
}

The following JUnit will suppress the getCurrency() method call:

import static org.junit.Assert.assertFalse;
import static org.powermock.api.support.membermodification.MemberMatcher.method;
import static org.powermock.api.support.membermodification.MemberModifier.suppress;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest(SuppressMethod.class)
public class SuppressMethodTest {

  @Test
  public void supresses_method() throws Exception {
    suppress(method(SuppressMethod.class, "getCurrency"));
    SuppressMethod method = new SuppressMethod();
    assertFalse(method.format("10").contains("$"));
  }
}

Note that the org.powermock.api.support.membermodification.MemberModifier.suppress method takes org.powermock.api.support.membermodification.MemberMatcher.method, the method that has to be suppressed. We passed the class and the method name getCurrency. Spell the method name correctly (because it is passed as a string) and without parenthesis. An immediate call to the getCurrency() method from the format() method is suppressed.

Stubbing private methods

You cannot access private methods of a class from outside the class. When a private method hides a testing impediment, and that method is invoked from a public or protected method, then you cannot JUnit test the public/protected method as you cannot bypass the private method call or stub the private method. However, PowerMockito allows us to stub private methods and enables us to write JUnit tests by suppressing the testing impediments.

The following example has a private method known as secretValue(); this method returns a secret value and the other public method exposeTheSecretValue() calls the secretValue() method. When we call the exposeTheSecretValue() method from a JUnit test, it always returns the same secret value, but if we need to change the secretValue() method for every method call, then we need to stub the private method's behavior:

package com.packt.legacy.powermockito;

public class PrivateMethod {

  private String secretValue(){
    return "#$$%^&*";
  }

  public String exposeTheSecretValue(){
    return secretValue();
  }
}

To stub the private method using PowerMockito, we need to create a spy object of the class and then stub the private method on the spy object. Remember that we cannot access a private method from outside the class; so when we stub a private method, we just pass the method name as a string value. We cannot call the method directly as its access scope is private. Hence, the name is passed as a string so that, using reflection, the method is found and stubbed. Make sure you spell the method name correctly. The following test exhibits the private method's stubbing:

package com.packt.legacy.powermockito;

import static org.junit.Assert.*;
import static org.powermock.api.mockito.PowerMockito.*;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest(PrivateMethod.class)
public class PrivateMethodTest {

  @Test
  public void stubs_private_methods() throws Exception {
    PrivateMethod privateMethodClass = spy(new PrivateMethod());
    when(privateMethodClass, "secretValue").thenReturn("123");

assertEquals("123", privateMethodClass.exposeTheSecretValue());
  }
}

The test stubs the secretValue method to return 123 and asserts the value by invoking the public method exposeTheSecretValue.

Stubbing final methods

Mockito cannot stub final methods, as Java doesn't allow us to override the final methods. However, when a final method hides a testing impediment, either we cannot unit test the method, or remove the final keyword and override the method for JUnit testing. This actually violates the encapsulation principle, but the good news is that PowerMockito allows us to stub the final methods.

The following example demonstrates the final method's stubbing:

package com.packt.legacy.powermockito;

public class FinalMethod {

  public final String getValue(){
    return null;
  }
}

The getValue() method is a final method, but we can mock the class and stub the final method using the @PrepareForTest annotation. The following JUnit test stubs the getValue() method:

@RunWith(PowerMockRunner.class)
@PrepareForTest(FinalMethod.class)
public class FinalMethodTest {

  private static final String A_STUBBED_VALUE = "A stubbed value";

  @Test
  public void stubs_final_methods() throws Exception {
    FinalMethod finalMethod = mock(FinalMethod.class);
    when(finalMethod.getValue()).thenReturn(A_STUBBED_VALUE);
    assertEquals(A_STUBBED_VALUE, finalMethod.getValue());
  }
}

Mocking final classes

You cannot extend a final class, but during JUnit testing, we encounter that third-party framework classes or external module classes are final and they hide testing impediments, but we cannot change the files as we don't have the permission to change the source code to make them nonfinal classes. Luckily, PowerMockito allows us to mock final classes. The following example will work with a final class:

public final class SystemVerifier {
  public boolean isInstallable(){
    return false;
  }
}

The SystemVerifier class is a final class and it has a public method isInstallable(); this method checks system prerequisites, such as RAM, disk space, and so on. If everything is okay, then returns true; we are hardcoding the method to return false.

The SoftwareInstaller class has a reference to the SystemVerifier class. When the SystemVerifier.isInstallable method returns true, it starts installing a software. The following is the SoftwareInstaller class:

public class SoftwareInstaller {
  private final SystemVerifier systemVerifier;

  public SoftwareInstaller(SystemVerifier systemVerifier) {
    this.systemVerifier = systemVerifier;
  }

  public boolean install(String packageName) {
    if (systemVerifier.isInstallable()) {
      // install something
      return true;
    }

    return false;
  }
}

We have already hardcoded the isInstallable() method to return false; to unit test the installation part, we need to stub the isInstallable() method to return true, but the SystemVerifier class is a final class, so we cannot stub the method.

The following PowerMockito JUnit test mocks the final class SystemVerifier and stubs the isInstallable() method to return true:

@RunWith(PowerMockRunner.class)
@PrepareForTest(SystemVerifier.class)
public class FinalClassTest {

  @Test
  public void mocks_final_classes() throws Exception {
    SystemVerifier systemVerifier = mock(SystemVerifier.class);
    when(systemVerifier.isInstallable()).thenReturn(true);

    SoftwareInstaller installer = new SoftwareInstaller(systemVerifier);
    assertTrue(installer.install("java"));
  }
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.174.253