@Test
public void testGetMenuSuccessfully() throws Exception {

    // setup
    url = url.addParameter(MERGER_KEY, ".merge");
    given(invocation.getMethodName()).willReturn("getMenu");
    given(invocation.getParameterTypes()).willReturn(new Class<?>[]{});
    given(invocation.getArguments()).willReturn(new Object[]{});
    given(invocation.getObjectAttachments()).willReturn(new HashMap<>())
            ;
    given(invocation.getInvoker()).willReturn(firstInvoker);
    firstInvoker = (Invoker) Proxy.newProxyInstance(getClass().getClassLoader(), new Class<?>[]{Invoker.class}, (proxy, method, args) -> {
        if ("getUrl".equals(method.getName())) {
            return url.addParameter(GROUP_KEY, "first");
        }
        if ("getInterface".equals(method.getName())) {
            return MenuService.class;
        }
        if ("invoke".equals(method.getName())) {
            return AsyncRpcResult.newDefaultAsyncResult(firstMenu, invocation);
        }
        return null;
    });
    secondInvoker = (Invoker) Proxy.newProxyInstance(getClass().getClassLoader(), new Class<?>[]{Invoker.class}, (proxy, method, args) -> {
        if ("getUrl".equals(method.getName())) {
            return url.addParameter(GROUP_KEY, "second");
        }
        if ("getInterface".equals(method.getName())) {
            return MenuService.class;
        }
        if ("invoke".equals(method.getName())) {
            return AsyncRpcResult.newDefaultAsyncResult(secondMenu, invocation);
        }
        return null;
    });
    given(directory.list(invocation)).willReturn(new ArrayList() {
        {
            add(firstInvoker);
            add(secondInvoker);
        }
    });
    given(directory.getUrl()).willReturn(url);
    given(directory.getConsumerUrl()).willReturn(url);
    given(directory.getConsumerUrl()).willReturn(url);
    given(directory.getInterface()).willReturn(MenuService.class);
    mergeableClusterInvoker = new MergeableClusterInvoker<MenuService>(directory);
    // invoke
    Result result = mergeableClusterInvoker.invoke(invocation);
    Assertions.assertTrue(result.getValue() instanceof Menu);
    Menu menu = (Menu) result.getValue();
    Map<String, List<String>> expected = new HashMap<String, List<String>>();
    merge(expected, firstMenuMap);
    merge(expected, secondMenuMap);
    assertEquals(expected.keySet(), menu.getMenus().keySet());
    for (Map.Entry<String, List<String>> entry : expected.entrySet()) {
        // FIXME: cannot guarantee the sequence of the merge result, check implementation in
        // MergeableClusterInvoker#invoke
        List<String> values1 = new ArrayList<String>(entry.getValue());
        List<String> values2 = new ArrayList<String>(menu.getMenus().get(entry.getKey()));
        Collections.sort(values1);
        Collections.sort(values2);
        assertEquals(values1, values2);
    }
}