模拟 ColumnDefinitions.Definition 确实 return 模拟,但在测试代码中表现得像 null
Mocking ColumnDefinitions.Definition does return mock, but is behaves like null in the tested code
我有以下代码准备模拟以使用 Cassandra 测试我的服务(我需要模拟 com.datastax.driver.core.ColumnDefinitions.Definition
):
@RunWith(PowerMockRunner.class)
public class TestMyClass{
private MyClass target;
@Before
public void setUp() throws Exception {
ColumnDefinitions mockColumnDefinitions=Mockito.mock(ColumnDefinitions.class);
Mockito.when(mockRow.getColumnDefinitions()).thenReturn(mockColumnDefinitions);
target= new MyClass();
Definition mockDef = Mockito.mock(Definition.class);
List<Definition> defList = new ArrayList<Definition>();
defList.add(mockDef);
Iterator mockIterator = Mockito.mock(Iterator.class);
Mockito.when(mockColumnDefinitions.iterator()).thenReturn(mockIterator);
Mockito.when(mockIterator.hasNext()).thenReturn(true, false);
Mockito.when(mockIterator.next()).thenReturn(mockDef);
Mockito.when(mockDef.getName()).thenReturn(NAME);
}
@Test
public void testMyMethod() throws Exception {
target.MyMethod();
}
}
这个地方的测试执行很顺利,我在不同的地方都有这种类型的代码,所以它应该可以工作。
在我正在测试的服务中,我有以下代码:
ColumnDefinitions colDef = row.getColumnDefinitions();
Iterator<Definition> defIterator = colDef.iterator();
while (defIterator.hasNext()) {
Definition def = defIterator.next();
String columnName = def.getName();
}
当我调试这段代码时,我发现 colDef
和 defIterator
都被成功模拟了。我在调试变量区域看到类似的东西:
Mock for Iterator, hashCode: 430126690
但是在 defIterator.next()
调用之后我看到虽然 def
是一个对象而不是 null,但它不像 Iterator
那样显示哈希码,而是我看到了这个:
com.sun.jdi.InvocationException occurred invoking method.
在调用这个字符串之后:
String columnName = def.getName();
如果 def 为空,我会立即得到 NullPointerException
。
我究竟做错了什么?
谢谢。
编辑 1 ________________________________________________________________________
我也试过用PowerMockito
用同样的方法代替,结果是一样的。
编辑 2 ________________________________________________________________________
我添加了整个测试方法代码。
创建这个问题已经有一段时间了。几天前我遇到了同样的问题,我已经通过以下方式解决了它(我希望我提出的解决方案对以后的人有所帮助):
首先,我想澄清一下,ColumnDefinition.Definition
class 是一个 public static
嵌套的 class,它有四个 private final
字段,只有一个构造函数:Definition (String keyspace, String table, String name and DataType type)
(更多细节请参考ColumnDefinitions.Definition javadoc and ColumnDefinitions source code). Therefore this nested class could not be mocked by Mockito nor Powermock,因为它有final
字段。
解决方案:
我必须创建一个真实的对象,而不是使用反射创建 class ColumnDefinition.Definition
的模拟对象,因此您可以按如下方式初始化 mockDef
对象:
Constructor<Definition> constructor = (Constructor<Definition>) Definition.class.getDeclaredConstructors()[0]; // as Definition only has one constructor, 0 will be passed as index
constructor.setAccessible(true);
Definition mockDef = constructor.newInstance("keyspace", "table", "name", null);
替换代码段中的这行代码:
Definition mockDef = Mockito.mock(Definition.class);
那么执行这行代码就不会再抛出NullPointerException了:
String columnName = def.getName();
我有以下代码准备模拟以使用 Cassandra 测试我的服务(我需要模拟 com.datastax.driver.core.ColumnDefinitions.Definition
):
@RunWith(PowerMockRunner.class)
public class TestMyClass{
private MyClass target;
@Before
public void setUp() throws Exception {
ColumnDefinitions mockColumnDefinitions=Mockito.mock(ColumnDefinitions.class);
Mockito.when(mockRow.getColumnDefinitions()).thenReturn(mockColumnDefinitions);
target= new MyClass();
Definition mockDef = Mockito.mock(Definition.class);
List<Definition> defList = new ArrayList<Definition>();
defList.add(mockDef);
Iterator mockIterator = Mockito.mock(Iterator.class);
Mockito.when(mockColumnDefinitions.iterator()).thenReturn(mockIterator);
Mockito.when(mockIterator.hasNext()).thenReturn(true, false);
Mockito.when(mockIterator.next()).thenReturn(mockDef);
Mockito.when(mockDef.getName()).thenReturn(NAME);
}
@Test
public void testMyMethod() throws Exception {
target.MyMethod();
}
}
这个地方的测试执行很顺利,我在不同的地方都有这种类型的代码,所以它应该可以工作。 在我正在测试的服务中,我有以下代码:
ColumnDefinitions colDef = row.getColumnDefinitions();
Iterator<Definition> defIterator = colDef.iterator();
while (defIterator.hasNext()) {
Definition def = defIterator.next();
String columnName = def.getName();
}
当我调试这段代码时,我发现 colDef
和 defIterator
都被成功模拟了。我在调试变量区域看到类似的东西:
Mock for Iterator, hashCode: 430126690
但是在 defIterator.next()
调用之后我看到虽然 def
是一个对象而不是 null,但它不像 Iterator
那样显示哈希码,而是我看到了这个:
com.sun.jdi.InvocationException occurred invoking method.
在调用这个字符串之后:
String columnName = def.getName();
如果 def 为空,我会立即得到 NullPointerException
。
我究竟做错了什么?
谢谢。
编辑 1 ________________________________________________________________________
我也试过用PowerMockito
用同样的方法代替,结果是一样的。
编辑 2 ________________________________________________________________________
我添加了整个测试方法代码。
创建这个问题已经有一段时间了。几天前我遇到了同样的问题,我已经通过以下方式解决了它(我希望我提出的解决方案对以后的人有所帮助):
首先,我想澄清一下,ColumnDefinition.Definition
class 是一个 public static
嵌套的 class,它有四个 private final
字段,只有一个构造函数:Definition (String keyspace, String table, String name and DataType type)
(更多细节请参考ColumnDefinitions.Definition javadoc and ColumnDefinitions source code). Therefore this nested class could not be mocked by Mockito nor Powermock,因为它有final
字段。
解决方案:
我必须创建一个真实的对象,而不是使用反射创建 class ColumnDefinition.Definition
的模拟对象,因此您可以按如下方式初始化 mockDef
对象:
Constructor<Definition> constructor = (Constructor<Definition>) Definition.class.getDeclaredConstructors()[0]; // as Definition only has one constructor, 0 will be passed as index
constructor.setAccessible(true);
Definition mockDef = constructor.newInstance("keyspace", "table", "name", null);
替换代码段中的这行代码:
Definition mockDef = Mockito.mock(Definition.class);
那么执行这行代码就不会再抛出NullPointerException了:
String columnName = def.getName();