如何仅在 x:th 调用时返回模拟项目



我在使用 PowerMock 时遇到了一个问题,如果我只想返回一次模拟项目,我就不得不创建丑陋的代码。例如,我有以下代码:

mockMap = spy(new HashMap());
HashMap<String, String> normalMap = new HashMap<>();
HashMap<String, String> normalMap2 = new HashMap<>();
HashMap<String, String> normalMap3 = new HashMap<>();
whenNew(HashMap.class).withNoArguments()
    .thenReturn(normalMap)
    .thenReturn(mockMap)
    .thenReturn(normalMap2)
    .thenReturn(normalMap3);

这当然有效,但感觉非常笨拙,特别是因为我需要为每个新调用创建一个新的哈希图。

所以我的问题是:有没有办法告诉 PowerMock 它应该在一定数量的调用后停止干扰?

编辑:看完答案后,我得到了以下内容:

final AtomicInteger count = new AtomicInteger(0);
whenNew(HashMap.class).withNoArguments().thenAnswer(invocation -> {
switch (count.incrementAndGet())
{
        case 1:
            return mockMap;
        default:
            return new HashMap<String, String>();
    }
});

但是,它使用以下代码为我提供了一个StackOverFlowError:

describe("test", () -> {
    beforeEach(() -> {
        mockStatic(HashMap.class);
        final AtomicInteger count = new AtomicInteger(0);
        whenNew(HashMap.class).withNoArguments().thenAnswer(invocation ->
        {
            switch (count.incrementAndGet())
            {
                case 5:
                    return mockMap;
                default:
                    return new HashMap<String, String>();
            }
        });
    });
    it("Crashes on getting a new HashMap", () -> {
        HashMap map = new HashMap<>();
        map.put("test", "test");
        HashMap normal = new HashMap<String, String>();
        expect(normal.containsValue("test")).toBeTrue();
    });
});

值得注意的是,在我的大型测试中,我没有 mockStatic(HashMap.class(会得到相同的错误(如果我删除 mockStatic 调用,我会摆脱这些错误(

一个有效的解决方案(但感觉像是一种解决方法(是通过将默认语句编辑为:

default:
    normalMap.clear();
    return normalMap;

您可以将 thenReturn 与多个参数一起使用,如下所示:

whenNew(HashMap.class).withNoArguments()
    .thenReturn(normalMap, mockMap, normalMap2, normalMap3);

或者像这样写你自己的答案:

whenNew(HashMap.withNoArguments()).doAnswer(new Answer() {
    private int count = 0;
    public Object answer(InvocationOnMock invocation) {
        // implement your logic
        // if (count ==0) etc.
    }
});
您可以使用

Mockito的org.mockito.stubbing.Answer

final AtomicInteger count = new AtomicInteger(0);
PowerMockito.whenNew(HashMap.class).withNoArguments()
    .thenAnswer(new Answer<HashMap<String, String>>() {
    @Override
    public HashMap<String, String> answer(InvocationOnMock invocation) throws Throwable {
        count.incrementAndGet();
        switch (count.get()) {
            case 1: // first call, return normalMap
                return normalMap;
            case 2: // second call, return mockMap
                return mockMap;
            case 3: // third call, return normalMap2
                return normalMap2;
            default: // forth call (and all calls after that), return normalMap3
                return normalMap3;
        }
    }
});

请注意,我必须使用 java.util.concurrent.atomic.AtomicInteger 并将其声明为 final 变量,原因有两个:

  • 匿名类中使用的变量必须是最终的(因为Java是这样定义的(
  • 如果我创建一个final int,我不能做count++

注意:在此解决方案中,您还必须将所有normalMap更改为final


实际上,如果您的所有normalMap都相同,您可以执行以下操作:

PowerMockito.whenNew(HashMap.class).withNoArguments()
    .thenAnswer(new Answer<HashMap<String, String>>() {
    @Override
    public HashMap<String, String> answer(InvocationOnMock invocation) throws Throwable {
        count.incrementAndGet();
        if (count.get() == 2) { // second call
            return mockMap;
        }
        return normalMap; // don't forget to make normalMap "final"
        // or if you prefer: return new HashMap<String, String>();
    }
});

PS:如本回答所述,除了使用 AtomicInteger ,您还可以在匿名类中创建一个int计数器(由您选择,因为两者都有效(:

PowerMockito.whenNew(HashMap.class).withNoArguments()
    .thenAnswer(new Answer<HashMap<String, String>>() {
    private int count = 0;
    @Override
    public HashMap<String, String> answer(InvocationOnMock invocation) throws Throwable {
        count++;
        if (count == 2) { // second call
            return mockMap;
        }
        return normalMap; // don't forget to make normalMap "final"
        // or if you prefer: return new HashMap<String, String>();
    }
});

这也适用于switch解决方案。

相关内容

  • 没有找到相关文章

最新更新