英文:
Mocking a method inside another method
问题
以下是翻译好的内容:
这是我正在测试的方法,我正在使用mockito进行模拟:
/**
* 同步获取单个zk节点下的所有子节点。
*
* @param zk
* zookeeper客户端
* @param node
* 节点路径
* @return 直接子节点
* @throws InterruptedException
* @throws IOException
*/
public static List<String> getChildrenInSingleNode(final ZooKeeper zk, final String node, long zkOpTimeoutMs)
throws InterruptedException, IOException, KeeperException.NoNodeException {
final GetChildrenCtx ctx = new GetChildrenCtx();
getChildrenInSingleNode(zk, node, new GenericCallback<List<String>>() {
@Override
public void operationComplete(int rc, List<String> ledgers) {
synchronized (ctx) {
if (Code.OK.intValue() == rc) {
ctx.children = ledgers;
}
ctx.rc = rc;
ctx.done = true;
ctx.notifyAll();
}
}
});
synchronized (ctx) {
long startTime = System.currentTimeMillis();
while (!ctx.done) {
try {
ctx.wait(zkOpTimeoutMs > 0 ? zkOpTimeoutMs : 0);
} catch (InterruptedException e) {
ctx.rc = Code.OPERATIONTIMEOUT.intValue();
ctx.done = true;
}
// 如果未收到get-children响应,则超时处理
if (zkOpTimeoutMs > 0 && (System.currentTimeMillis() - startTime) >= zkOpTimeoutMs) {
ctx.rc = Code.OPERATIONTIMEOUT.intValue();
ctx.done = true;
}
}
}
if (Code.NONODE.intValue() == ctx.rc) {
throw new KeeperException.NoNodeException("在调用路径为 " + node + " 的getChildren时发生NoNode异常");
} else if (Code.OK.intValue() != ctx.rc) {
throw new IOException("从节点 " + node + " 获取子节点时出错");
}
return ctx.children;
}
这是我的测试类:
@RunWith(value= Parameterized.class)
public class ZkUtilsGetChildrenTest {
// ...(测试类的其余部分)
@Test
public void testGetChildrenInSingleNode() {
boolean realResult;
try {
List<String> children = ZkUtils.getChildrenInSingleNode(zkc, path, timeout);
assertThat(children, is(childPaths));
} catch (Exception e) {
realResult = false;
e.printStackTrace();
assertEquals(expectedResult, realResult);
}
}
}
如果您有任何进一步的疑问,请随时问我。
英文:
This is the method i'm testing and i'm using mockito for mocking:
/**
* Sync get all children under single zk node.
*
* @param zk
* zookeeper client
* @param node
* node path
* @return direct children
* @throws InterruptedException
* @throws IOException
*/
public static List<String> getChildrenInSingleNode(final ZooKeeper zk, final String node, long zkOpTimeoutMs)
throws InterruptedException, IOException, KeeperException.NoNodeException {
final GetChildrenCtx ctx = new GetChildrenCtx();
getChildrenInSingleNode(zk, node, new GenericCallback<List<String>>() {
@Override
public void operationComplete(int rc, List<String> ledgers) {
synchronized (ctx) {
if (Code.OK.intValue() == rc) {
ctx.children = ledgers;
}
ctx.rc = rc;
ctx.done = true;
ctx.notifyAll();
}
}
});
synchronized (ctx) {
long startTime = System.currentTimeMillis();
while (!ctx.done) {
try {
ctx.wait(zkOpTimeoutMs > 0 ? zkOpTimeoutMs : 0);
} catch (InterruptedException e) {
ctx.rc = Code.OPERATIONTIMEOUT.intValue();
ctx.done = true;
}
// timeout the process if get-children response not received
// zkOpTimeoutMs.
if (zkOpTimeoutMs > 0 && (System.currentTimeMillis() - startTime) >= zkOpTimeoutMs) {
ctx.rc = Code.OPERATIONTIMEOUT.intValue();
ctx.done = true;
}
}
}
if (Code.NONODE.intValue() == ctx.rc) {
throw new KeeperException.NoNodeException("Got NoNode on call to getChildren on path " + node);
} else if (Code.OK.intValue() != ctx.rc) {
throw new IOException("Error on getting children from node " + node);
}
return ctx.children;
}
And this is my test class:
@RunWith(value= Parameterized.class)
public class ZkUtilsGetChildrenTest {
private boolean expectedResult;
private ZooKeeper zkc ;
private String path;
private long timeout;
private static List<String> paths = Arrays.asList("/ledgers/000/000/000/001", "/ledgers/000/000/000/002",
"/ledgers/000/000/000/003");
private static List<String> childPaths = Arrays.asList("001", "002", "003");
// ZooKeeper related variables
private static ZooKeeperUtil zkUtil = new ZooKeeperUtil();
@Mock
ZkUtils.GetChildrenCtx mocked = mock(ZkUtils.GetChildrenCtx.class) ;
@BeforeClass
public static void setUp() throws Exception {
zkUtil.startCluster();
ZooKeeper initializerZkc = new ZooKeeper(zkUtil.getZooKeeperConnectString(), 10000, null);
for (String path : paths ){
ZkUtils.createFullPathOptimistic(initializerZkc, path, "data".getBytes() , ZooDefs.Ids.OPEN_ACL_UNSAFE ,
CreateMode.CONTAINER);
}
}
@AfterClass
public static void tearDown() throws Exception {
zkUtil.killCluster();
}
@Parameterized.Parameters
public static Collection<Object[]> getTestParameters() throws IOException {
return Arrays.asList(new Object[][]{
{false , "null" , "/ledgers/000/000/000/004" , 0},
{true , "new" , "/ledgers/000/000/000" , 1000 },
{false , "wrong" , "/ledgers/000/000/000/00b" , -1},
{false , "new" , "/ledgers/000/000/00b" , 0 },//aggiunto per migliorare statement e branch coverage
{false , "new" , "/ledgers/000/000/003" , 1 },//aggiunto per migliorare statement e branch coverage
{false , "mock" , "/ledgers/000/000" , 1000 },//aggiunto per migliorare statement coverage
});
}
public ZkUtilsGetChildrenTest(boolean expectedResult ,String zkc , String path , long timeout) throws IOException {
if(zkc == "null"){
this.zkc = null;
}else if( zkc == "wrong"){
this.zkc = new ZooKeeper("wrongString", 10000, null);
}else if(zkc == "new"){
this.zkc = new ZooKeeper(zkUtil.getZooKeeperConnectString(), 10000, null);
}else if(zkc == "mock"){
//TODO MOCK THE INNER METHOD
this.zkc = new ZooKeeper(zkUtil.getZooKeeperConnectString(), 10000, null);
when(mocked).thenThrow(new InterruptedException());
}
this.expectedResult = expectedResult;
this.path = path;
this.timeout = timeout;
}
@Test
public void testGetChildrenInSingleNode() {
boolean realResult;
try {
List<String> children = ZkUtils.getChildrenInSingleNode(zkc, path, timeout);
assertThat(children, is(childPaths));
} catch (Exception e) {
realResult = false;
e.printStackTrace();
assertEquals(expectedResult, realResult);
}
}
}
I would like to ask you how can i mock the method ctx.wait(zkOpTimeoutMs > 0 ? zkOpTimeoutMs : 0); so that i can trigger the catch block which follows this statement : if i called this method i would have mocked an istance of this class and call the method on that mock but since is not me who calls this method but it's called by the method under test, how can i properly mock it?
Good day to everyone!
答案1
得分: 2
你可以使用Powermock来模拟创建新对象,如果这是可用的,并且您不能或不想重构现有代码。使用Powermock并非没有缺点,但这是一种强大的方式,可以对这种情况以及其他情况(静态类/方法和私有/受保护的类/方法/字段)获得更精细的控制。
英文:
You can use Powermock to mock the creation of new objects if that is something available to you and you cannot or do not want to refactor the existing code. Using Powermock is not without its own downsides, but is a powerful way to gain more granular control over this and other cases (static class/methods and private/protected classes/methods/fields).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论