4

The test code is:

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.time.LocalTime;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import org.junit.runner.RunWith;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
public class HelloWorldByHour {

    private static LocalTime REST_START_TIME = LocalTime.of(14, 0);
    private static LocalTime REST_END_TIME = LocalTime.of(16, 0);

    public static void main(String[] args) throws Exception {
        HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);
        server.createContext("/greeting", new MyHandler());
        server.setExecutor(null); // creates a default executor
        server.start();
    }

    private static class MyHandler implements HttpHandler {
        public void handle(HttpExchange t) throws IOException {
            LocalTime time = LocalTime.now();
            String response;

            if (time.isAfter(REST_START_TIME) && time.isBefore(REST_END_TIME)) {
                response = "Nap time";
            } else {
                response = "Hello World";
            }

            t.sendResponseHeaders(200, response.length());
            OutputStream os = t.getResponseBody();
            os.write(response.getBytes());
            os.close();
        }
    }

}

When running the test I get:

org.mockito.exceptions.misusing.UnfinishedStubbingException: Unfinished stubbing detected here: -> at HelloWorldByHourTest.testMain(HelloWorldByHourTest.java:35)

E.g. thenReturn() may be missing. Examples of correct stubbing: when(mock.isOk()).thenReturn(true); when(mock.isOk()).thenThrow(exception); doThrow(exception).when(mock).someVoidMethod(); Hints: 1. missing thenReturn() 2. you are trying to stub a final method, you naughty developer! 3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed

my pom.xml is

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>server</groupId>
    <artifactId>server</artifactId>
    <version>1.0-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>(whatever version is current)</version>
                <configuration>
                    <!-- or whatever version you use -->
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-api-mockito</artifactId>
            <version>1.6.5</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-core</artifactId>
            <version>1.6.5</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-module-junit4</artifactId>
            <version>1.6.5</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-module-junit4</artifactId>
            <version>RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
        </dependency>
    </dependencies>
</project>

The test code is:

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

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.time.LocalTime;

import static org.powermock.api.mockito.PowerMockito.mockStatic;
import static org.powermock.api.mockito.PowerMockito.when;

@RunWith(PowerMockRunner.class)
@PrepareForTest(LocalTime.class)
public class HelloWorldByHourTest {

    private String sendRequest() throws IOException {
        URL url = new URL("localhost:8080/greeting");
        BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()));
        String strTemp = "";
        StringBuilder sb = new StringBuilder();
        while (null != (strTemp = br.readLine())) {
            sb.append(strTemp);
        }
        return sb.toString();
    }

    @Test
    public void testMain() throws Exception {

        mockStatic(LocalTime.class);
        when(LocalTime.now()).thenReturn(LocalTime.of(15, 0));
        HelloWorldByHour.main(null);
        String response = sendRequest();
        Assert.assertEquals("Nap time", response);
    }
}

Any idea what's wrong?

traveh
  • 2,700
  • 3
  • 27
  • 44
  • Have you posted the right code? Your exception is in `HelloWorldByHourTest` and it looks like what you have posted comes from `HelloWorldByHour`. – Sam Jul 19 '16 at 18:07
  • Yeah I posted the wrong code - adding the test code now. – traveh Jul 19 '16 at 18:08

2 Answers2

2

The problem is that you call a static method on LocalDate in your when and thenReturn

Try something like that:

    LocalTime time = LocalTime.of(15,0);
    mockStatic(LocalTime.class);
    when(LocalTime.now()).thenReturn(time);
k5_
  • 5,450
  • 2
  • 19
  • 27
  • I tried this and it seems to be better, but now I'm getting `java.lang.VerifyError: Bad type on operand stack Exception Details: Location: com/sun/net/httpserver/spi/HttpServerProvider$1.run()Ljava/lang/Object; @27: invokestatic Reason: Type 'sun/net/httpserver/DefaultHttpServerProvider' (current frame, stack[0]) is not assignable to 'com/sun/net/httpserver/spi/HttpServerProvider'` – traveh Jul 19 '16 at 19:52
2

With this call when(LocalTime.now()).thenReturn(LocalTime.of(15, 0)); you're kind of fitting under:

3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed.

Basically you've mocked statically the LocalTime class but you're also invoking the static LocalTime.of(15, 0) method while defining the behavior of the LocalTime.now().

Depending on what you want to do, I suppose a workaround would be to create a mock of LocalTime before mocking the static methods, something along the lines of:

@Test
public void testMain() throws Exception {
    // create a mock
    LocalTime mockLocalTime = mock(LocalTime.class);
    // TODO define behaviour of mockLocalTime

    // mock the static methods
    mockStatic(LocalTime.class);
    when(LocalTime.now()).thenReturn(mockLocalTime);

    // invoke object under test
    HelloWorldByHour.main(null);
    String response = sendRequest();

    // interaction verification and/or assersions
    Assert.assertEquals("Nap time", response);
}
Morfic
  • 15,178
  • 3
  • 51
  • 61