[英]Mockito Spy Does Not See Correct Primitive Value
我面臨以下問題,當間接更新間諜 object 上的字段時,間諜不會看到原始字段的更新,而只會在參考上看到一次。
舉個例子:
import org.junit.Test;
import org.mockito.Mockito;
import java.util.function.Consumer;
import java.util.concurrent.atomic.AtomicBoolean;
public class MyTest {
class Actor {
Consumer<Boolean> consumer;
void init(Consumer<Boolean> consumer){
this.consumer = consumer;
}
void act(boolean flag){
this.consumer.apply(flag);
}
}
class TestClass {
boolean field = true;
AtomicBoolean refField = new AtomicBoolean(true);
TestClass(Actor actor){
actor.init( flag -> {
System.out.println("Changing field to " + flag);
field = flag;
refField.set(flag);
});
}
void call(){
this.doSomething(field);
}
void callRef(){
this.doSomething(refField.get());
}
void doSomething(boolean flag){
System.out.println("#doSomething(" + flag + ")");
}
}
@Test
public void test(){
// given an actor and a spied TestClass
Actor actor = new Actor();
TestClass spy = Mockito.spy(new TestClass(actor));
// when invoking the action with the primitive
spy.call();
// then expect correct invocation
Mockito.verify(spy, Mockito.times(1)).doSomething( true );
// when invoking the action with the ref field
spy.callRef();
// then expect correct invocation
Mockito.verify(spy, Mockito.times(2)).doSomething( true );
// when changing the flag to 'false'
actor.act( false );
// and invoking the action with the refField
spy.callRef();
// then expect correct invocation
Mockito.verify(spy, Mockito.times(1)).doSomething(false);
// when invoking the action with the primitive
spy.call();
// then method is NOT invoked as expected !!!!!!!
Mockito.verify(spy, Mockito.times(2)).doSomething(false);
}
}
最后一次驗證將失敗,因為該方法是使用第一個原始值調用的。
我想知道為什么會這樣? 這是預期的行為嗎? 運行上述測試,將產生以下日志記錄:
#doSomething(true)
#doSomething(true)
Changing flag to false
#doSomething(false)
#doSomething(true)
我希望用false
調用最后一個日志語句。
對上述有什么見解嗎?
PS:版本= mockito-core:2.25.0
您的系統中有 2 個 TestClass object 實例:
間諜是從原始實例創建的。
boolean field
)被復制,每個 TestClass 持有refField
)讓我們進行以下更改以觀察:
TestClass(Actor actor){
actor.init( flag -> {
// print referenced TestClass instance
System.out.println("from actor: " + TestClass.this);
System.out.println("Changing field to " + flag);
field = flag;
refField.set(flag);
});
}
@Test
public void test(){
// given an actor and a spied TestClass
Actor actor = new Actor();
TestClass testClassOriginal = new TestClass(actor);
TestClass spy = Mockito.spy(testClassOriginal);
System.out.println("org" + testClassOriginal);
System.out.println("spy" + spy);
// when changing the flag to 'false'
actor.act( false );
System.out.println("After change org: " + testClassOriginal.field);
System.out.println("After change spy: " + spy.field);
}
這給出了以下 output:
org: mypackage.MyTest$TestClass@4218500f
spy: mypackage.MyTest$TestClass$MockitoMock$2115616475@5c10f1c3
from actor: mypackage.MyTest$TestClass@4218500f
Changing field to false
After change org: false
After change spy: true
你可以清楚地看到:
可能的解決方案
你需要讓演員看到間諜,而不是原來的object。 為此,必須將 TestClass 的創建與注冊消費者分離。
class TestClass {
boolean field = true;
AtomicBoolean refField = new AtomicBoolean(true);
TestClass(){
}
void consumeFlag(Boolean flag) {
System.out.println("from actor: " + this);
System.out.println("Changing field to " + flag);
field = flag;
refField.set(flag);
}
// ...
}
@Test
public void test(){
// given an actor and a spied TestClass
Actor actor = new Actor();
TestClass spy = Mockito.spy(new TestClass());
actor.init(spy::consumeFlag);
// ...
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.