【问题标题】:Mockito - PowerMock. Mocking the method callMockito - PowerMock。模拟方法调用
【发布时间】:2015-11-04 21:10:49
【问题描述】:

我想为下面的方法编写一个测试,在这个方法中,我要模拟的另外两个方法调用是 getterToMock(),第二个是 static 方法调用,作为模拟 static 方法使用 Mockito 是不可能的 我使用 PowerMock 但我仍然得到NullPointerException

@Resource
private Bar bar;

public int methodToTest(String arg1) {
    String crucialValue = SomeClass.methodToMock(bar.getterToMock());
        Method Logic Here 
        ....
}

我的测试如下

private BarContext barContext = mock(BarContext.class)
@Mock
private Bar bar;

@Test
public void testTheMethod(){
    PowerMockito.mockStatic(SomeClass.class);
    PowerMockito.doReturn(barContext).when(bar).getterToMock();
    PowerMockito.doReturn("Bingo").when(SomeClass.methodToMock(barContext));
    Foo foo = new Foo();
    foo.methodToTest("foo");
}

我认为问题在于我没有正确地模拟 @Resource 注释属性

编辑添加实际代码

@WebService
public class FileUploadServiceImpl implements FileUploadService {

private final String soapFilePath = "target/;
private final static Map<String, String> userFileMap = new HashMap<>();
private final static AtomicInteger id = new AtomicInteger();

@Resource
private WebServiceContext webServiceContext;

@Override
public int createFile(@WebParam String name) {
    String username = Utils.getUsername(webServiceContext.getMessageContext());

    try {
        File userDir = new File(filePath + username);
        userDir.mkdir();
        File file = new File(userDir.getPath() + "/" + name);
        file.createNewFile();
        userFileMap.put(username + "_" + id.get(), name);
    } catch (IOException e) {
        LOG.error(e.getMessage(), e);
        e.printStackTrace();
    }
    return id.getAndIncrement();
   }
}

在 Utils 类中获取用户名

public static String getUsername(MessageContext context){
            Map httpHeaders = (Map) context.get(MessageContext.HTTP_REQUEST_HEADERS);
            if(httpHeaders != null){
                List<String> auth = (List<String>) httpHeaders.get("Authorization");
                if (auth != null && auth.get(0).startsWith("Basic")){
                    String base64Credentials = auth.get(0).substring("Basic".length()).trim();
                    String credentials = new String(Base64.getDecoder().decode(
                            base64Credentials.getBytes(Charset.forName("UTF-8"))));
                    return credentials.split(":", 2)[0];
                }
            }
        return null;
      }

测试

@RunWith(PowerMockRunner.class)
@PrepareForTest(FileUploadServiceImpl.class)
public class ServiceTest {
private String username = "10237832";
private FileUploadService service;
private MessageContext messageContext = mock(MessageContext.class);

@Mock
private WebServiceContext webServiceContext;

@Test
public void startUploadFileTest(){
    service = new FileUploadServiceImpl();
    mockStatic(Utils.class);
    when(webServiceContext.getMessageContext()).thenReturn(messageContext);
    when(Utils.getUsername(messageContext)).thenReturn(username);
    service.startUpload("test_file");
  }
}

异常堆栈跟踪

java.lang.NullPointerException
    at org.example.utils.Utils.getUsername(Utils.java:47)
    at org.example.services.ServiceTest.startUploadFileTest(ServiceTest.java:42)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:310)
    at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:88)
    at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:96)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:294)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:127)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:282)
    at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:86)
    at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:207)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:146)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:120)
    at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:33)
    at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:45)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:122)
    at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:106)
    at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
    at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)

【问题讨论】:

  • 您在设置模拟之前致电methodToTest,据我所知...您希望它如何工作?
  • 只是复制粘贴问题,见编辑
  • 您在哪里确切地遇到了异常?如果你能提供一个简短但完整的程序来演示这个问题,那真的很有帮助......
  • PowerMockito.doReturn(barContext).when(bar).getterToMock() 抛出异常;
  • 当您使用 powermockito 时,它将在内部获取其 mockito 依赖项,如果您在 pom 文件中明确定义任何 mockito 版本,则将其删除。类似的问题在这里解决了stackoverflow.com/a/31718124/5038825

标签: java unit-testing mocking mockito powermockito


【解决方案1】:

为什么不将用户名的获取抽象到一个类中呢?

    class UsernameRetriever {

        private final WebServiceContext webServiceContext;

        UsernameRetriever(WebServiceContext webServiceContext) {
           this.webServiceContext = webServiceContext;
        }


        String getUsernameFromContext() {
            return Utils.getUsername(webServiceContext.getMessageContext());
        }

    }

然后你会通过构造函数将 this 注入你的类(我不记得 @Inject 和构造函数的语法,所以你自己检查一下)。

@WebService
public class FileUploadServiceImpl implements FileUploadService {

// SHOULD BE STATIC FINAL IF IT'S A CONSTANT - IT SHOULD BE PARAMETRIZED BTW
private static final String soapFilePath = "target/;
// YOU'RE GOING TO HAVE A RACE CONDITION - HASH MAP IS NOT THREAD SAFE
private final static Map<String, String> userFileMap = new HashMap<>();
private final static AtomicInteger id = new AtomicInteger();

private final UsernameRetriver usernameRetriever;

@Inject
public FileUploadServiceImpl(WebServiceContext webServiceContext) {
    this.usernameRetriever = new UsernameRetriever(webServiceContext);
}


@Inject
// for testing purposes
FileUploadServiceImpl(UsernameRetriever usernameRetriever) {
    this.usernameRetriever = usernameRetriever
}

@Override
public int createFile(@WebParam String name) {
    String username = usernameRetriever.getUsernameFromContext();

    try {
        File userDir = new File(filePath + username);
        userDir.mkdir();
        File file = new File(userDir.getPath() + "/" + name);
        file.createNewFile();
        userFileMap.put(username + "_" + id.get(), name);
    } catch (IOException e) {
        LOG.error(e.getMessage(), e);
        e.printStackTrace();
    }
    return id.getAndIncrement();
   }
}

这样: * 不需要 Powermock * 你有单一职责 * 你已经正确编写了代码;)

顺便说一句: * 你的代码不是线程安全的——它会在生产中崩溃 * 不可参数化(路径“目标”是固定的)

【讨论】:

    猜你喜欢
    • 2014-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多