下面是这个类:
public class A {
public final SqlOperator op;
public final ImmutableList<RexNode> operands;
public final RelDataType type;
protected A(RelDataType type,SqlOperator op,List<? extends RexNode> operands) {
assert type != null : "precondition: type != null";
assert op != null : "precondition: op != null";
assert operands != null : "precondition: operands != null";
this.type = type;
this.op = op;
this.operands = ImmutableList.copyOf(operands);
assert op.getKind() != null : op;
assert op.validRexOperands(operands.size(), Litmus.THROW) : this;
}我想模拟A类,但是将"operands“字段的值设置为一个空列表。字段是final,当我模拟这个类时,我不能在构造函数之外修改它。
我试着使用反射,但这对Mockito不起作用。
需要测试用例的代码:
public static String extractGranularity(A call) {
if (call.getKind() != SqlKind.FLOOR || call.getOperands().size() != 2) {
return null;
}
final B flag = (B) call.operands.get(1); // This is the problem area
final TimeUnitRange timeUnit = (TimeUnitRange) flag.getValue();
if (timeUnit == null) {
return null;
}
return timeUnitSwitch(timeUnit);
}发布于 2017-07-14 14:19:30
好了,这是基于你发布的类的一些东西(我假设真正的类有点不同):
package so45078998;
import com.google.common.collect.ImmutableList;
import java.util.List;
public class A {
public final SqlOperator op;
public final ImmutableList<RexNode> operands;
public final RelDataType type;
protected A(RelDataType type, SqlOperator op, List<? extends RexNode> operands) {
assert type != null : "precondition: type != null";
assert op != null : "precondition: op != null";
assert operands != null : "precondition: operands != null";
this.type = type;
this.op = op;
this.operands = ImmutableList.copyOf(operands);
assert op.getKind() != null : op;
assert op.validRexOperands(operands.size(), Litmus.THROW) : this;
}
public Object getKind() {
return op.getKind();
}
public ImmutableList<RexNode> getOperands() {
return operands;
}
static class SqlOperator{
private Object kind;
public Object getKind() {
return kind;
}
void setKind(final Object kind) {
this.kind = kind;
}
boolean validRexOperands(int size, Litmus litmus) {
return true;
}
}
static class RexNode{
private Object value;
public Object getValue() {
return value;
}
void setValue(final Object value) {
this.value = value;
}
}
static class RelDataType{}
static enum Litmus{ THROW }
}
// ------------------------------------------------------
package so45078998;
public class ToTest {
public static String extractGranularity(A call) {
if (call.getKind() != SqlKind.FLOOR || call.getOperands().size() != 2) {
return null;
}
final B flag = (B) call.operands.get(1); // This is the problem area
final TimeUnitRange timeUnit = (TimeUnitRange) flag.getValue();
if (timeUnit == null) {
return null;
}
return timeUnitSwitch(timeUnit);
}
private static String timeUnitSwitch(final TimeUnitRange timeUnit) {
return "OK";
}
enum SqlKind { FLOOR, OTHER }
static class TimeUnitRange {}
static class B extends A.RexNode {}
}和测试类(两个测试在这里都是绿色的):
package so45078998;
import org.junit.Assert;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
public class ToTestTest {
@Test
public void testExtractGranularityWithKindNotFloor() throws Exception {
ToTest.B rexNode1 = new ToTest.B();
ToTest.B rexNode2 = new ToTest.B();
List<A.RexNode> operands = new ArrayList<>();
operands.add(rexNode1);
operands.add(rexNode2);
final A.RelDataType relDataType = new A.RelDataType();
final A.SqlOperator sqlOperator = new A.SqlOperator();
sqlOperator.setKind(ToTest.SqlKind.OTHER);
A a = new A(relDataType, sqlOperator, operands);
Assert.assertNull(ToTest.extractGranularity(a));
}
@Test
public void testExtractGranularity() throws Exception {
ToTest.B rexNode1 = new ToTest.B();
ToTest.B rexNode2 = new ToTest.B();
rexNode2.setValue(new ToTest.TimeUnitRange());
List<A.RexNode> operands = new ArrayList<>();
operands.add(rexNode1);
operands.add(rexNode2);
final A.RelDataType relDataType = new A.RelDataType();
final A.SqlOperator sqlOperator = new A.SqlOperator();
sqlOperator.setKind(ToTest.SqlKind.FLOOR);
A a = new A(relDataType, sqlOperator, operands);
Assert.assertEquals("OK", ToTest.extractGranularity(a));
}
}这是因为测试类和被测试类共享相同的包名(因此您可以直接调用new A(...))。
否,如果您想抑制某些A行为,请使用间谍,并在需要时使用它来控制行为。
我希望这能有所帮助。
发布于 2017-07-27 15:18:37
也许你可以尝试使用Unsafe:
sun.misc.Unsafe unsafe = null;
try {
final PrivilegedExceptionAction<sun.misc.Unsafe> action = () -> {
Field unsafe = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
unsafe.setAccessible(true);
return (sun.misc.Unsafe) unsafe.get(null);
};
unsafe = AccessController.doPrivileged(action);
} catch (Exception e) {
throw new RuntimeException("Unable to load unsafe", e);
}
long operandsOffset = unsafe.objectFieldOffset(
A.class.getDeclaredField("operands"));
A instance = // your instance of A
ImmutableList<RexNode> yourOverridingList = ...
unsafe.getAndSetObject(instance, operandsOffset, yourOverridingList);发布于 2017-07-13 19:26:26
封装,你这个笨蛋!
封装是隐藏类的实际实现细节。因此,在您的示例中,现在使用myA.operands来访问实际的操作数。这可能会带来一些麻烦。不是让所有属性都公开,而是让它们成为private并添加一些访问器方法:
public class A {
private final ImmutableList<RexNode> operands;
// rest of attributes and constructor...
public ImmutableList<RexNode> getOperands() {
return operands;
}
}不仅你会遵循一个很好的实践,而且模仿它也会更容易:
A myA = mock(A.class);
Mockito.when(myA.getOperands())
.thenReturn(/* what you want it to return */);https://stackoverflow.com/questions/45078998
复制相似问题