私は非常に同様のプロジェクト、すべてのJava、SpringBoot、とMavenの一握りを持っています。それらのすべてが1つの同じ名前のクラス、およびほぼ同じ内容を持っています。私は、私が説明するつもりですが、私はかなり確信してディテールが偶然の一致であることだ問題でそれらの1、クラスの追加メソッドを追加しました。
各プロジェクトはまた、非常によく似たクラスに対応するテストクラスがあり、その試験クラスのスケルトンは、各クラスに同じです。試験クラスが有する@InjectMocks
試験(CUT)の下クラスのために、二つ@Mock
の注釈、CUTのインスタンス変数に対応するのひとつ。
試験クラスが持っている@Before
テストで使用されるインスタンス変数を作成する方法。
テストクラスのすべてのバリエーションは、「持っています@RunWith(MockitoJUnitRunner.class)
」。
私は「良い」のテストのいずれかを実行し、@Beforeメソッドの最初の行にブレークポイントを設定し、変数ペインで「この」変数を見れば、私はモック-EDのインスタンス変数@ 2の種類を見ます"$ MockitoMock" で終わります。
私は「悪い」のテストで同じことを行う場合は、モック-ED変数@ 2のタイプは、「で終わりません$MockitoMock
」。実際には、これらは、対応するクラス、ない嘲笑のクラスの通常のインスタンスであるように思われます。
さらに好奇心、「悪い」テストで、私は「への明示的な呼び出しを作ってみましたinstvar = mock(clazz.class)
で」@Before
方法、と私はをクリックしたときに、それらの上にI工程の後に、インスタンス変数の型は、しかし、STILL嘲笑タイプではありませんインスタンス変数、のtoStringパネルショー「Mock for ..., hashCode: 1028811481
」。私はこの時点で「再開」した場合、私は、その値のtoString言う「その同じインスタンスで、伝えられるところで嘲笑クラスにブレークポイントをヒットすることができますMock for ...
」。
それは言葉で問題です。今、私はいくつかのコードを示しますね。
「悪い」テストクラスのここでの一部:
@RunWith(MockitoJUnitRunner.class)
public class RestClientTest {
@InjectMocks
RestClient restClient;
@Mock
RestClientFactory restClientFactory;
@Mock
RestTemplate restTemplate;
HttpEntity<String> requestEntity;
@Before
public void setup() {
requestEntity = new HttpEntity<>(new HttpHeaders());
restClientFactory = mock(RestClientFactory.class);
restTemplate = mock(RestTemplate.class);
ReflectionTestUtils.setField(restClient, "restClientFactory", restClientFactory);
}
ここでは「良い」テストクラスの一部です:
@RunWith(MockitoJUnitRunner.class)
public class RestClientTest {
@InjectMocks
RestClient restClient;
@Mock
RestClientFactory restClientFactory;
@Mock
RestTemplate restTemplate;
HttpEntity<String> requestEntity;
@Before
public void setup() {
requestEntity = new HttpEntity<>(new HttpHeaders());
}
私は「良い」と「悪い」プロジェクトの両方がmockito-コアのバージョン2.15.0を使用していることを決定しました。
アップデート:
私はそれが注釈処理からここに行くので、私は悪いと良いケースの両方の動作を見ることができるので、そこに悪いテストで「モック」コールに足を踏み入れると、ブレークポイントを設定しようとしました。
ここで私は良いケースで見たものです:
私はライン65までステップオーバーと「createMock()」に足を踏み入れました。それはMockUtilクラスに私を置きます:
「mockMaker」のタイプは、「org.mockito.internal.creation.bytebuddy.ByteBuddyMockMaker」です。
Iは、ライン35に段差及び「mockMaker.createMock()」メソッドに段差:
それでは、最初からやり直しと「悪い」ケースを実行してみましょう:
今、私たちは「mockMaker」のタイプが良い場合と異なっていることがわかります。タイプは「org.mockito.internal.creation.bytebuddy.InlineByteBuddyMockMaker」です。
I'm not going to continue to step through this, but this path does produce the "fake mock" with the different toString value.
Now that I think about it, this instance is like a "spy" in that it's managed by Mockito, but all the methods call the original class method by default. I have no clue why it takes a different path here.
I would hope that this is enough information to give a clue to someone who better understands how this works.
The type of "mockMaker" [in the "good" case] is "org.mockito.internal.creation.bytebuddy.ByteBuddyMockMaker".
Now [in the "bad" case] we see that the type of "mockMaker" is DIFFERENT from the good case. The type is "org.mockito.internal.creation.bytebuddy.InlineByteBuddyMockMaker".
So, the "good" project is using the default mock-maker, which uses subclassing — see ByteBuddyMockMaker.java — while the "bad" project is using a non-default mock-maker that tries to use Java instrumentation to avoid subclassing: InlineByteBuddyMockMaker.java. That matches up with the behavior difference that you observed
According to the Javadoc for InlineByteBuddyMockMaker:
This mock maker must to be activated explicitly for supporting mocking final types and methods:
This mock maker can be activated by creating the file
/mockito-extensions/org.mockito.plugins.MockMaker
containing the textmock-maker-inline
ororg.mockito.internal.creation.bytebuddy.InlineByteBuddyMockMaker
.
これが起こっている理由を理解するので、あなたはどのように見つけるためにあなたのクラスパスに検索する/mockito-extensions/org.mockito.plugins.MockMaker
リソースがそこに終わるされます。