Mockito 2 - LyonJug - 2017-01-26

Mockito 2 - LyonJug - 2017-01-26

Mockito n’est pas le premier framework de mock, il fait partie d’une évolution du genre. Dans cette présentation nous allons voir quelles sont les évolutions apportées par la version 2 : support Java 8, amélioration des API, qualité du code de test, support Android, continuous delivery, capacité de configuration. Nous allons aussi soulever le capot pour étudier la création d’un mock. Et enfin nous regarderons vers le futur pour Mockito 3.

------

The slides are french but here's the english description :
Mockito is not the first mock framework out there, it is part of long ongoing effort. In this talk we will see what Mockito 2 brings with version 2 : Java 8 support, API improvements, mock code quality, Android support, continuous delivery, configurability. We will also look at how mocks are made. And we will look at what is the prelimiary plan for Mockito 3.

F31c7fbcbb0766d0632d96fd7e74b649?s=128

Brice Dutheil

January 26, 2017
Tweet

Transcript

  1. 2.

    Qui suis-je ? Back to basics Mockito 2 Nouvelles features

    Mockito 2 Changements internes Mockito 3 What’s next Release delivery continuum
  2. 3.

    Qui suis-je ? Back to basics Mockito 2 Nouvelles features

    Mockito 2 Changements internes Mockito 3 What’s next Release delivery continuum
  3. 5.

    Qui suis-je ? Back to basics Mockito 2 Nouvelles features

    Mockito 2 Changements internes Mockito 3 What’s next Release delivery continuum
  4. 7.
  5. 11.
  6. 12.

    IMethods a_lot_of_methods = mock(IMethods.class); MethodsImpl i_m_a_partial_mock = spy(new MethodsImpl()); given(a_lot_of_methods.varargs("Am",

    "stram", "gram", "Pic", "et", "pic", "et", "colégram", "Bour", "et", "bour", "et", "ratatam", "Am", "stram", "gram")).willReturn(42); // actual tested code
  7. 14.

    IMethods a_lot_of_methods = mock(IMethods.class); MethodsImpl i_m_a_partial_mock = spy(new MethodsImpl()); given(a_lot_of_methods.varargs("Am",

    "stram", "gram", "Pic", "et", "pic", "et", "colégram", "Bour", "et", "bour", "et", "ratatam", "Am", "stram", "gram")).willReturn(42); // actual tested code verify(a_lot_of_methods).varargs(any());
  8. 16.

    @Mock IMethods a_lot_of_methods; @Spy MethodsImpl i_m_a_partial_mock = new MethodsImpl(); given(a_lot_of_methods.varargs("Am",

    "stram", "gram", "Pic", "et", "pic", "et", "colégram", "Bour", "et", "bour", "et", "ratatam", "Am", "stram", "gram")).willReturn(42); // actual tested code verify(a_lot_of_methods).varargs(any());
  9. 21.

    @Mock IMethods a_lot_of_methods; @Spy MethodsImpl i_m_a_partial_mock = new MethodsImpl(); given(a_lot_of_methods.varargs("Am",

    "stram", "gram", "Pic", "et", "pic", "et", "colégram", "Bour", "et", "bour", "et", "ratatam", "Am", "stram", "gram")).willReturn(42); // actual tested code verify(a_lot_of_methods).varargs(any()); ArgumentCaptor<Object> the_arg = ArgumentCaptor.forClass(Long.class); verify(i_m_a_partial_mock).oneArg(the_arg.capture());
  10. 22.

    @Mock IMethods a_lot_of_methods; @Spy MethodsImpl i_m_a_partial_mock = new MethodsImpl(); given(a_lot_of_methods.varargs("Am",

    "stram", "gram", "Pic", "et", "pic", "et", "colégram", "Bour", "et", "bour", "et", "ratatam", "Am", "stram", "gram")) .will(AdditionalAnswers.returnsArgAt(9)); // actual tested code verify(a_lot_of_methods).varargs(any()); ArgumentCaptor<Object> The_arg = ArgumentCaptor.forClass(Long.class); verify(i_m_a_partial_mock).oneArg(The_arg.capture()); Pour les cas plus rares
  11. 23.

    Qui suis-je ? Back to basics Mockito 2 Nouvelles features

    Mockito 2 Changements internes Mockito 3 What’s next Release delivery continuum
  12. 24.
  13. 29.

    public Optional<Thing> returns_optional() { } mock.returns_optional() public Stream<Thing> returns_a_stream() {

    } mock.returns_a_stream() Retourne Optional.empty() Retourne une stream vide
  14. 33.

    String forBoolean(Boolean value); when(mock.forBoolean(isNull())).thenReturn("ok"); String forInteger(Integer value); when(mock.forInteger(notNull())).thenReturn("ok"); String forMap(Map<String,

    String> map); when(mock.forMap(anyMap())).thenReturn("ok"); String oneArg(CurrencyDescription value); when(mock.oneArg(any())).thenReturn("$ USD"); when(mock.oneArg(any(EuroDescription.class))).thenReturn("€ EUR"); Java 8
  15. 35.

    String forBoolean(Boolean value); when(mock.forBoolean(isNull())).thenReturn("ok"); String forInteger(Integer value); when(mock.forInteger(notNull())).thenReturn("ok"); String forMap(Map<String,

    String> map); when(mock.forMap(anyMap())).thenReturn("ok"); String oneArg(CurrencyDescription value); when(mock.oneArg(any())).thenReturn("$ USD"); when(mock.oneArg(any(EuroDescription.class))).thenReturn("€ EUR"); Java 8
  16. 36.

    String forBoolean(Boolean value); when(mock.forBoolean(isNull(Boolean.class))).thenReturn("ok"); String forInteger(Integer value); when(mock.forInteger(notNull(Integer.class))).thenReturn("ok"); String forMap(Map<String,

    String> map); when(mock.forMap(anyMapOf(String.class, String.class))).thenReturn("2"); String oneArg(CurrencyDescription value); when(mock.oneArg((CurrencyDescription) any())).thenReturn("matched"); when(mock.oneArg(any(EuroDescription.class))).thenReturn("€ EUR"); Java 7
  17. 39.

    String forBoolean(Boolean value); when(mock.forBoolean((Boolean) isNull())).thenReturn("ok"); String forInteger(Integer value); when(mock.forInteger((Integer) notNull())).thenReturn("ok");

    String forMap(Map<String, String> map); when(mock.forMap((Map<String, String>) anyMap())).thenReturn("ok"); String oneArg(CurrencyDescription value); when(mock.oneArg((CurrencyDescription) any())).thenReturn("$ USD"); when(mock.oneArg(any(EuroDescription.class))).thenReturn("€ EUR");
  18. 45.

    given(mock.returns_a_long()).willAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable

    { // custom code ... return something; } }); given(mock.returns_a_long()).willAnswer(invocation -> /* custom code ... */); Mockito 1.x
  19. 46.

    given(mock.returns_a_long()).willAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable

    { // custom code ... return something; } }); given(mock.returns_a_long()).willAnswer(invocation -> /* custom code ... */); Représente une invocation sur le mock
  20. 52.

    Java 8 permet d’écrire du code concret dans les méthodes

    d’interface connues sous le nom default methods
  21. 55.

    @Rule public MockitoRule rulez = MockitoJUnit.rule(); @Mock private Consumer<String> consumer1;

    @Mock private Consumer<String> consumer2; @Test public void working_with_default_methods() { consumer1.andThen(consumer2) .accept("hi"); }
  22. 56.

    @Rule public MockitoRule rulez = MockitoJUnit.rule(); @Mock private Consumer<String> consumer1;

    @Mock private Consumer<String> consumer2; @Test public void working_with_default_methods() { consumer1.andThen(consumer2) .accept("hi"); verify(consumer1).accept("hi"); verify(consumer2).accept("hi"); }
  23. 57.

    @Rule public MockitoRule rulez = MockitoJUnit.rule(); @Mock private Consumer<String> consumer1;

    @Mock private Consumer<String> consumer2; @Test public void working_with_default_methods() { consumer1.andThen(consumer2) .accept("hi"); verify(consumer1).accept("hi"); verify(consumer2).accept("hi"); } NullPointerException
  24. 58.

    @Rule public MockitoRule rulez = MockitoJUnit.rule(); @Mock private Consumer<String> consumer1;

    @Mock private Consumer<String> consumer2; @Test public void working_with_default_methods() { consumer1.andThen(consumer2) .accept("hi"); verify(consumer1).accept("hi"); verify(consumer2).accept("hi"); } Retourne null
  25. 59.

    @Rule public MockitoRule rulez = MockitoJUnit.rule(); @Mock private Consumer<String> consumer1;

    @Mock private Consumer<String> consumer2; @Test public void working_with_default_methods() { consumer1.andThen(consumer2) .accept("hi"); verify(consumer1).accept("hi"); verify(consumer2).accept("hi"); } default method
  26. 60.

    @Rule public MockitoRule rulez = MockitoJUnit.rule(); @Mock private Consumer<String> consumer1;

    @Mock private Consumer<String> consumer2; @Test public void working_with_default_methods() { consumer1.andThen(consumer2) .accept("hi"); verify(consumer1).accept("hi"); verify(consumer2).accept("hi"); } default method default Consumer<T> andThen(Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; }
  27. 62.

    Un spy est un mock partiel. Par défaut invoque les

    méthodes concrètes mais permet de modifier le comportement
  28. 65.

    Consumer<String> consumer1 = spy(Consumer.class); Consumer<String> consumer2 = spy(Consumer.class); consumer1.andThen(consumer2) .accept("hi");

    verify(consumer1).accept("hi"); verify(consumer2).accept("hi"); Code concret de andThen exécuté
  29. 66.
  30. 69.

    public class Tested { private Dep1 dep1; private Dep2 dep2;

    private Dep3 dep3; public void behavior() { dep1.sub_behaviour(); dep2.sub_behaviour(); dep3.sub_behaviour(); } }
  31. 70.

    @Rule public MockitoRule rulez = MockitoJUnit.rule(); @Mock private Dep1 dep1;

    @Mock private Dep2 dep2; @Mock private Dep3 dep3; @InjectMocks Tested tested; @Test public void should_behave_in_that_case() { given(dep1.sub_behaviour()).willReturn("A"); given(dep2.sub_behaviour()).willReturn("A"); given(dep3.sub_behaviour()).willReturn("A"); tested.behavior(); //... }
  32. 71.

    public class Tested { private Dep1 dep1; private Dep2 dep2;

    private Dep3 dep3; public void behavior() { dep1.sub_behaviour(); dep2.sub_behaviour(); dep3.sub_behaviour(); } } Feature supprimée
  33. 72.

    public class Tested { private Dep1 dep1; private Dep2 dep2;

    private Dep3 dep3; public void behavior() { dep3.sub_behaviour(); } } Feature supprimée
  34. 74.

    [MockitoHint] QualityTest.should_behave_in_that_case (see javadoc for MockitoHint): [MockitoHint] 1. Unused ->

    at QualityTest.should_behave_in_that_case(QualityTest.java:22) [MockitoHint] 2. Unused -> at QualityTest.should_behave_in_that_case(QualityTest.java:23)
  35. 75.

    @Rule public MockitoRule rulez = MockitoJUnit.rule(); @Mock private Dep1 dep1;

    @Mock private Dep2 dep2; @Mock private Dep3 dep3; @InjectMocks Tested tested; @Test public void should_behave_in_that_case() { given(dep1.sub_behaviour()).willReturn("A"); given(dep2.sub_behaviour()).willReturn("A"); given(dep3.sub_behaviour()).willReturn("A"); tested.behavior(); //... }
  36. 76.

    @Rule public MockitoRule rulez = MockitoJUnit.rule() .silent(); @Mock private Dep1

    dep1; @Mock private Dep2 dep2; @Mock private Dep3 dep3; @InjectMocks Tested tested; @Test public void should_behave_in_that_case() { given(dep1.sub_behaviour()).willReturn("A"); given(dep2.sub_behaviour()).willReturn("A"); given(dep3.sub_behaviour()).willReturn("A"); tested.behavior(); //... } Éteint les warnings dans la console
  37. 77.

    @Rule public MockitoRule rulez = MockitoJUnit.rule() .strictness(STRICT_STUBS); @Mock private Dep1

    dep1; @Mock private Dep2 dep2; @Mock private Dep3 dep3; @InjectMocks Tested tested; @Test public void should_behave_in_that_case() { given(dep1.sub_behaviour()).willReturn("A"); given(dep2.sub_behaviour()).willReturn("A"); given(dep3.sub_behaviour()).willReturn("A"); tested.behavior(); //... } Fait échouer le test
  38. 78.

    @Rule public MockitoRule rulez = MockitoJUnit.rule() .strictness(STRICT_STUBS); @Mock private Dep1

    dep1; @Mock private Dep2 dep2; @Mock private Dep3 dep3; @InjectMocks Tested tested; @Test public void should_behave_in_that_case() { given(dep1.sub_behaviour()).willReturn("A"); given(dep2.sub_behaviour()).willReturn("A"); given(dep3.sub_behaviour()).willReturn("A"); tested.behavior(); //... } Possiblement le défaut dans Mockito 3
  39. 79.

    org.mockito.exceptions.misusing.UnnecessaryStubbingException: Unnecessary stubbings detected. Clean & maintainable test code requires

    zero unnecessary code. Following stubbings are unnecessary (click to navigate to relevant line of code): 1. -> at QualityTest.should_behave_in_that_case(QualityTest.java:23) 2. -> at QualityTest.should_behave_in_that_case(QualityTest.java:24) Please remove unnecessary stubbings or use 'silent' option. More info: javadoc for UnnecessaryStubbingException class.
  40. 81.
  41. 83.

    Le tout premier mécanisme consiste à créer dans ses sources

    une classe org.mockito.configuration.MockitoConfiguration
  42. 88.

    package org.mockito.configuration; public class MockitoConfiguration implements IMockitoConfiguration { @Override public

    Answer<Object> getDefaultAnswer() { return ...; } @Override public AnnotationEngine getAnnotationEngine() { return ...; } @Override public boolean cleansStackTrace() { return ...; } @Override public boolean enableClassCache() { return ...; } }
  43. 89.

    package org.mockito.configuration; public class MockitoConfiguration extends DefaultMockitoConfiguration implements IMockitoConfiguration {

    @Override public Answer<Object> getDefaultAnswer() { return ...; } @Override public AnnotationEngine getAnnotationEngine() { return ...; } @Override public boolean cleansStackTrace() { return ...; } @Override public boolean enableClassCache() { return ...; } }
  44. 90.

    package org.mockito.configuration; public class MockitoConfiguration extends DefaultMockitoConfiguration implements IMockitoConfiguration {

    @Override public boolean cleansStackTrace() { return ...; } @Override public boolean enableClassCache() { return ...; } }
  45. 99.

    Pourquoi ne pas utiliser ServiceLoader ? Ajouté dans le niveau

    d’API 9 (~2011) Utilise dans le dossier META-INF hors il est supprimé à la création de l’APK
  46. 104.

    MockMaker, génère un mock InstantiatorProvider, instancie un mock AnnotationEngine, gère

    les annotations StackTraceCleanerProvider, néttoie les stack traces
  47. 105.

    MockMaker, génère un mock InstantiatorProvider, instancie un mock AnnotationEngine, gère

    les annotations StackTraceCleanerProvider, néttoie les stack traces PluginSwitch, gère l’activation d’un plugin externe
  48. 107.

    /** * Serves as a marker for dummy mocks, when

    processed creates * a mock using {@code Mcokito.mock(FieldType.class)} */ public @interface Dummy { }
  49. 108.

    /** * Serves as a marker for dummy mocks, when

    processed creates * a mock using {@code Mcokito.mock(FieldType.class)} */ public @interface Dummy { } @Dummy Dependency just_for_compilation;
  50. 110.

    public class DummyAnnotationEngine implements AnnotationEngine { @Override public void process(Class<?>

    clazz, Object testInstance) { testInstance.getClass().getDeclaredFields() } }
  51. 111.

    public class DummyAnnotationEngine implements AnnotationEngine { @Override public void process(Class<?>

    clazz, Object testInstance) { Arrays.stream(testInstance.getClass().getDeclaredFields()) } }
  52. 112.

    public class DummyAnnotationEngine implements AnnotationEngine { @Override public void process(Class<?>

    clazz, Object testInstance) { Arrays.stream(testInstance.getClass().getDeclaredFields()) .filter(field -> field.isAnnotationPresent(Dummy.class)) } }
  53. 113.

    public class DummyAnnotationEngine implements AnnotationEngine { @Override public void process(Class<?>

    clazz, Object testInstance) { Arrays.stream(testInstance.getClass().getDeclaredFields()) .filter(field -> field.isAnnotationPresent(Dummy.class)) .forEach(field -> { }); } }
  54. 114.

    public class DummyAnnotationEngine implements AnnotationEngine { @Override public void process(Class<?>

    clazz, Object testInstance) { Arrays.stream(testInstance.getClass().getDeclaredFields()) .filter(field -> field.isAnnotationPresent(Dummy.class)) .forEach(field -> { field.set(testInstance, Mockito.mock(field.getType())); }); } }
  55. 115.

    public class DummyAnnotationEngine implements AnnotationEngine { @Override public void process(Class<?>

    clazz, Object testInstance) { Arrays.stream(testInstance.getClass().getDeclaredFields()) .filter(field -> field.isAnnotationPresent(Dummy.class)) .forEach(field -> { field.setAccessible(true); field.set(testInstance, Mockito.mock(field.getType())); }); } }
  56. 116.

    public class DummyAnnotationEngine implements AnnotationEngine { @Override public void process(Class<?>

    clazz, Object testInstance) { Arrays.stream(testInstance.getClass().getDeclaredFields()) .filter(field -> field.isAnnotationPresent(Dummy.class)) .forEach(field -> { try { field.setAccessible(true); field.set(testInstance, Mockito.mock(field.getType())); } catch (Exception e) { } }); } }
  57. 117.

    public class DummyAnnotationEngine implements AnnotationEngine { @Override public void process(Class<?>

    clazz, Object testInstance) { Arrays.stream(testInstance.getClass().getDeclaredFields()) .filter(field -> field.isAnnotationPresent(Dummy.class)) .forEach(field -> { try { field.setAccessible(true); field.set(testInstance, Mockito.mock(field.getType())); } catch (Exception e) { throw new IllegalStateException(format("Could not initialize @Dummy field '%s'", field.getName()), e); } }); } }
  58. 123.

    public class DummyAnnotationEngine implements AnnotationEngine { @Override public void process(Class<?>

    clazz, Object testInstance) { Arrays.stream(testInstance.getClass().getDeclaredFields()) .filter(field -> field.isAnnotationPresent(Dummy.class)) .forEach(field -> { try { field.setAccessible(true); field.set(testInstance, Mockito.mock(field.getType())); } catch (Exception e) { throw new IllegalStateException(format("Could not initialize @Dummy field '%s'", field.getName()), e); } }); } }
  59. 124.

    public class DummyAnnotationEngine implements AnnotationEngine { AnnotationEngine internalEngine = new

    InjectingAnnotationEngine(); @Override public void process(Class<?> clazz, Object testInstance) { Arrays.stream(testInstance.getClass().getDeclaredFields()) .filter(field -> field.isAnnotationPresent(Dummy.class)) .forEach(field -> { try { field.setAccessible(true); field.set(testInstance, Mockito.mock(field.getType())); } catch (Exception e) { throw new IllegalStateException(format("Could not initialize @Dummy field '%s'", field.getName()), e); } }); } }
  60. 125.

    public class DummyAnnotationEngine implements AnnotationEngine { AnnotationEngine internalEngine = new

    InjectingAnnotationEngine(); @Override public void process(Class<?> clazz, Object testInstance) { Arrays.stream(testInstance.getClass().getDeclaredFields()) .filter(field -> field.isAnnotationPresent(Dummy.class)) .forEach(field -> { try { field.setAccessible(true); field.set(testInstance, Mockito.mock(field.getType())); } catch (Exception e) { throw new IllegalStateException(format("Could not initialize @Dummy field '%s'", field.getName()), e); } }); internalEngine.process(clazz, testInstance); } } Invoque le processeur interne
  61. 126.

    public class DummyAnnotationEngine implements AnnotationEngine { AnnotationEngine internalEngine = new

    InjectingAnnotationEngine(); @Override public void process(Class<?> clazz, Object testInstance) { internalEngine.process(clazz, testInstance); } } API interne
  62. 128.
  63. 133.
  64. 137.

    dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude

    group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:25.1.0' // ... testCompile 'junit:junit:4.12' // ... }
  65. 138.

    dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude

    group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:25.1.0' // ... testCompile 'junit:junit:4.12' testCompile 'org.mockito:mockito-core:2.+' // ... }
  66. 139.

    dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude

    group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:25.1.0' // ... testCompile 'junit:junit:4.12' testCompile 'org.mockito:mockito-core:2.+' androidTestCompile 'org.mockito:mockito-core:2.+' androidTestCompile 'com.linkedin.dexmaker:dexmaker-mockito:2.2.0' // ... }
  67. 140.

    dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude

    group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:25.1.0' // ... testCompile 'junit:junit:4.12' testCompile 'org.mockito:mockito-core:2.+' androidTestCompile 'org.mockito:mockito-core:2.+' androidTestCompile 'com.linkedin.dexmaker:dexmaker-mockito:2.2.0' // ... } dexmaker a été repris par linkedin Et mis à jour pour fonctionner avec Mockito 2
  68. 143.

    dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude

    group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:25.1.0' // ... testCompile 'junit:junit:4.12' testCompile 'org.mockito:mockito-core:2.+' androidTestCompile 'org.mockito:mockito-core:2.+' androidTestCompile 'com.linkedin.dexmaker:dexmaker-mockito:2.2.0' // ... }
  69. 144.

    dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude

    group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:25.1.0' // ... testCompile 'junit:junit:4.12' testCompile 'org.mockito:mockito-core:2.+' androidTestCompile 'org.mockito:mockito-core:2.+' androidTestCompile 'org.mockito:mockito-android:2.6.+' // ... }
  70. 152.

    public final class FinalClass { public String foo() { return

    "foo"; } } FinalClass finalClass = mock(FinalClass.class); given(finalClass.foo()).willReturn("bar");
  71. 153.

    public final class FinalClass { public String foo() { return

    "foo"; } } FinalClass finalClass = mock(FinalClass.class); given(finalClass.foo()).willReturn("bar"); assertThat(proxy.foo()).isEqualTo("bar");
  72. 154.

    public final class FinalClass { public String foo() { return

    "foo"; } } FinalClass finalClass = mock(FinalClass.class); given(finalClass.foo()).willReturn("bar"); assertThat(proxy.foo()).isEqualTo("bar"); My Life List … [✔ ] Mocking final
  73. 157.
  74. 159.

    Vous ne voulez pas mocker HashMap, classe non finale, son

    comportement change entre chaque JDK
  75. 160.

    Sur votre CI vos tests peuvent être verts mais le

    code exécuté en production peut être erroné
  76. 161.

    Qui suis-je ? Back to basics Mockito 2 Nouvelles features

    Mockito 2 Changements internes Mockito 3 What’s next Release delivery continuum
  77. 166.

    Après des mois à coder et étudier les alternatives, Rafael

    nous a proposé sa librairie : byte-buddy http://stackoverflow.com/questions/2261947/are-there-alternatives-to-cglib/9823788#9823788
  78. 171.

    DynamicType.Builder<T> builder = byteBuddy.subclass(features.mockedType) .name(nameFor(features.mockedType)) .ignoreAlso(isGroovyMethod()) .annotateType(features.mockedType.getAnnotations()) .implement(new ArrayList<Type>(features.interfaces)) .method(matcher)

    .intercept(to(DispatcherDefaultingToRealMethod.class)) .transform(withModifiers(SynchronizationState.PLAIN, Visibility.PUBLIC)) .attribute(INCLUDING_RECEIVER) .method(isHashCode()) .intercept(to(MockMethodInterceptor.ForHashCode.class)) .method(isEquals()) .intercept(to(MockMethodInterceptor.ForEquals.class)) .serialVersionUid(42L) .defineField("mockitoInterceptor", MockMethodInterceptor.class, PRIVATE) .implement(MockAccess.class) .intercept(FieldAccessor.ofBeanProperty()); if (features.serializableMode == SerializableMode.ACROSS_CLASSLOADERS) { builder = builder.implement(CrossClassLoaderSerializableMock.class) .intercept(to(MockMethodInterceptor.ForWriteReplace.class)); } if (readReplace != null) { builder = builder.defineMethod("readObject", void.class, Visibility.PRIVATE) .withParameters(ObjectInputStream.class) .throwing(ClassNotFoundException.class, IOException.class) .intercept(readReplace); } return builder.make() .load(new MultipleParentClassLoader.Builder() .append(features.mockedType) .append(features.interfaces) .append(currentThread().getContextClassLoader()) .append(MockAccess.class, DispatcherDefaultingToRealMethod.class) .append(MockMethodInterceptor.class, MockMethodInterceptor.ForHashCode.class,
  79. 172.

    DynamicType.Builder<T> builder = byteBuddy.subclass(features.mockedType) .name(nameFor(features.mockedType)) .ignoreAlso(isGroovyMethod()) .annotateType(features.mockedType.getAnnotations()) .implement(new ArrayList<Type>(features.interfaces)) .method(matcher)

    .intercept(to(DispatcherDefaultingToRealMethod.class)) .transform(withModifiers(SynchronizationState.PLAIN, Visibility.PUBLIC)) .attribute(INCLUDING_RECEIVER) .method(isHashCode()) .intercept(to(MockMethodInterceptor.ForHashCode.class)) .method(isEquals()) .intercept(to(MockMethodInterceptor.ForEquals.class)) .serialVersionUid(42L) .defineField("mockitoInterceptor", MockMethodInterceptor.class, PRIVATE) .implement(MockAccess.class) .intercept(FieldAccessor.ofBeanProperty()); if (features.serializableMode == SerializableMode.ACROSS_CLASSLOADERS) { builder = builder.implement(CrossClassLoaderSerializableMock.class) .intercept(to(MockMethodInterceptor.ForWriteReplace.class)); } if (readReplace != null) { builder = builder.defineMethod("readObject", void.class, Visibility.PRIVATE) .withParameters(ObjectInputStream.class) .throwing(ClassNotFoundException.class, IOException.class) .intercept(readReplace); } return builder.make() .load(new MultipleParentClassLoader.Builder() .append(features.mockedType) .append(features.interfaces) .append(currentThread().getContextClassLoader()) .append(MockAccess.class, DispatcherDefaultingToRealMethod.class) .append(MockMethodInterceptor.class, MockMethodInterceptor.ForHashCode.class, Configuration de la classe
  80. 173.

    DynamicType.Builder<T> builder = byteBuddy.subclass(features.mockedType) .name(nameFor(features.mockedType)) .ignoreAlso(isGroovyMethod()) .annotateType(features.mockedType.getAnnotations()) .implement(new ArrayList<Type>(features.interfaces)) .method(matcher)

    .intercept(to(DispatcherDefaultingToRealMethod.class)) .transform(withModifiers(SynchronizationState.PLAIN, Visibility.PUBLIC)) .attribute(INCLUDING_RECEIVER) .method(isHashCode()) .intercept(to(MockMethodInterceptor.ForHashCode.class)) .method(isEquals()) .intercept(to(MockMethodInterceptor.ForEquals.class)) .serialVersionUid(42L) .defineField("mockitoInterceptor", MockMethodInterceptor.class, PRIVATE) .implement(MockAccess.class) .intercept(FieldAccessor.ofBeanProperty()); if (features.serializableMode == SerializableMode.ACROSS_CLASSLOADERS) { builder = builder.implement(CrossClassLoaderSerializableMock.class) .intercept(to(MockMethodInterceptor.ForWriteReplace.class)); } if (readReplace != null) { builder = builder.defineMethod("readObject", void.class, Visibility.PRIVATE) .withParameters(ObjectInputStream.class) .throwing(ClassNotFoundException.class, IOException.class) .intercept(readReplace); } return builder.make() .load(new MultipleParentClassLoader.Builder() .append(features.mockedType) .append(features.interfaces) .append(currentThread().getContextClassLoader()) .append(MockAccess.class, DispatcherDefaultingToRealMethod.class) .append(MockMethodInterceptor.class, MockMethodInterceptor.ForHashCode.class, Configuration de la classe Configuration du classloader pour le chargement de la classe du mock
  81. 175.

    DynamicType.Builder<T> builder = byteBuddy.subclass(features.mockedType) .name(nameFor(features.mockedType)) .ignoreAlso(isGroovyMethod()) .annotateType(features.mockedType.getAnnotations()) .implement(new ArrayList<Type>(features.interfaces)) .method(matcher)

    .intercept(to(DispatcherDefaultingToRealMethod.class)) .transform(withModifiers(SynchronizationState.PLAIN, Visibility.PUBLIC)) .attribute(INCLUDING_RECEIVER) .method(isHashCode()) .intercept(to(MockMethodInterceptor.ForHashCode.class)) .method(isEquals()) .intercept(to(MockMethodInterceptor.ForEquals.class)) .serialVersionUid(42L) .defineField("mockitoInterceptor", MockMethodInterceptor.class, Visibility.PRIVATE) .implement(MockAccess.class) .intercept(FieldAccessor.ofBeanProperty()); Type de modification : Sous classe
  82. 176.

    DynamicType.Builder<T> builder = byteBuddy.subclass(features.mockedType) .name(nameFor(features.mockedType)) .ignoreAlso(isGroovyMethod()) .annotateType(features.mockedType.getAnnotations()) .implement(new ArrayList<Type>(features.interfaces)) .method(matcher)

    .intercept(to(DispatcherDefaultingToRealMethod.class)) .transform(withModifiers(SynchronizationState.PLAIN, Visibility.PUBLIC)) .attribute(INCLUDING_RECEIVER) .method(isHashCode()) .intercept(to(MockMethodInterceptor.ForHashCode.class)) .method(isEquals()) .intercept(to(MockMethodInterceptor.ForEquals.class)) .serialVersionUid(42L) .defineField("mockitoInterceptor", MockMethodInterceptor.class, Visibility.PRIVATE) .implement(MockAccess.class) .intercept(FieldAccessor.ofBeanProperty()); Défini le nom qualifié Packages signés, etc.
  83. 177.

    DynamicType.Builder<T> builder = byteBuddy.subclass(features.mockedType) .name(nameFor(features.mockedType)) .ignoreAlso(isGroovyMethod()) .annotateType(features.mockedType.getAnnotations()) .implement(new ArrayList<Type>(features.interfaces)) .method(matcher)

    .intercept(to(DispatcherDefaultingToRealMethod.class)) .transform(withModifiers(SynchronizationState.PLAIN, Visibility.PUBLIC)) .attribute(INCLUDING_RECEIVER) .method(isHashCode()) .intercept(to(MockMethodInterceptor.ForHashCode.class)) .method(isEquals()) .intercept(to(MockMethodInterceptor.ForEquals.class)) .serialVersionUid(42L) .defineField("mockitoInterceptor", MockMethodInterceptor.class, Visibility.PRIVATE) .implement(MockAccess.class) .intercept(FieldAccessor.ofBeanProperty()); Le nom de la classe contiendra : MockitoMock
  84. 178.

    DynamicType.Builder<T> builder = byteBuddy.subclass(features.mockedType) .name(nameFor(features.mockedType)) .ignoreAlso(isGroovyMethod()) .annotateType(features.mockedType.getAnnotations()) .implement(new ArrayList<Type>(features.interfaces)) .method(matcher)

    .intercept(to(DispatcherDefaultingToRealMethod.class)) .transform(withModifiers(SynchronizationState.PLAIN, Visibility.PUBLIC)) .attribute(INCLUDING_RECEIVER) .method(isHashCode()) .intercept(to(MockMethodInterceptor.ForHashCode.class)) .method(isEquals()) .intercept(to(MockMethodInterceptor.ForEquals.class)) .serialVersionUid(42L) .defineField("mockitoInterceptor", MockMethodInterceptor.class, Visibility.PRIVATE) .implement(MockAccess.class) .intercept(FieldAccessor.ofBeanProperty()); On ne mocke pas les méthodes générées par groovy
  85. 179.

    DynamicType.Builder<T> builder = byteBuddy.subclass(features.mockedType) .name(nameFor(features.mockedType)) .ignoreAlso(isGroovyMethod()) .annotateType(features.mockedType.getAnnotations()) .implement(new ArrayList<Type>(features.interfaces)) .method(matcher)

    .intercept(to(DispatcherDefaultingToRealMethod.class)) .transform(withModifiers(SynchronizationState.PLAIN, Visibility.PUBLIC)) .attribute(INCLUDING_RECEIVER) .method(isHashCode()) .intercept(to(MockMethodInterceptor.ForHashCode.class)) .method(isEquals()) .intercept(to(MockMethodInterceptor.ForEquals.class)) .serialVersionUid(42L) .defineField("mockitoInterceptor", MockMethodInterceptor.class, Visibility.PRIVATE) .implement(MockAccess.class) .intercept(FieldAccessor.ofBeanProperty()); Copie les annotations du type mocké
  86. 180.

    DynamicType.Builder<T> builder = byteBuddy.subclass(features.mockedType) .name(nameFor(features.mockedType)) .ignoreAlso(isGroovyMethod()) .annotateType(features.mockedType.getAnnotations()) .implement(new ArrayList<Type>(features.interfaces)) .method(matcher)

    .intercept(to(DispatcherDefaultingToRealMethod.class)) .transform(withModifiers(SynchronizationState.PLAIN, Visibility.PUBLIC)) .attribute(INCLUDING_RECEIVER) .method(isHashCode()) .intercept(to(MockMethodInterceptor.ForHashCode.class)) .method(isEquals()) .intercept(to(MockMethodInterceptor.ForEquals.class)) .serialVersionUid(42L) .defineField("mockitoInterceptor", MockMethodInterceptor.class, Visibility.PRIVATE) .implement(MockAccess.class) .intercept(FieldAccessor.ofBeanProperty()); Extra interfaces
  87. 181.

    DynamicType.Builder<T> builder = byteBuddy.subclass(features.mockedType) .name(nameFor(features.mockedType)) .ignoreAlso(isGroovyMethod()) .annotateType(features.mockedType.getAnnotations()) .implement(new ArrayList<Type>(features.interfaces)) .method(matcher)

    .intercept(to(DispatcherDefaultingToRealMethod.class)) .transform(withModifiers(SynchronizationState.PLAIN, Visibility.PUBLIC)) .attribute(INCLUDING_RECEIVER) .method(isHashCode()) .intercept(to(MockMethodInterceptor.ForHashCode.class)) .method(isEquals()) .intercept(to(MockMethodInterceptor.ForEquals.class)) .serialVersionUid(42L) .defineField("mockitoInterceptor", MockMethodInterceptor.class, PRIVATE) .implement(MockAccess.class) .intercept(FieldAccessor.ofBeanProperty()); Quelle méthode à intercepter (toutes par défaut)
  88. 182.

    DynamicType.Builder<T> builder = byteBuddy.subclass(features.mockedType) .name(nameFor(features.mockedType)) .ignoreAlso(isGroovyMethod()) .annotateType(features.mockedType.getAnnotations()) .implement(new ArrayList<Type>(features.interfaces)) .method(matcher)

    .intercept(to(DispatcherDefaultingToRealMethod.class)) .transform(withModifiers(SynchronizationState.PLAIN, Visibility.PUBLIC)) .attribute(INCLUDING_RECEIVER) .method(isHashCode()) .intercept(to(MockMethodInterceptor.ForHashCode.class)) .method(isEquals()) .intercept(to(MockMethodInterceptor.ForEquals.class)) .serialVersionUid(42L) .defineField("mockitoInterceptor", MockMethodInterceptor.class, PRIVATE) .implement(MockAccess.class) .intercept(FieldAccessor.ofBeanProperty()); Type du callback Dispatcher : Classe mockito annotée
  89. 183.

    DynamicType.Builder<T> builder = byteBuddy.subclass(features.mockedType) .name(nameFor(features.mockedType)) .ignoreAlso(isGroovyMethod()) .annotateType(features.mockedType.getAnnotations()) .implement(new ArrayList<Type>(features.interfaces)) .method(matcher)

    .intercept(to(DispatcherDefaultingToRealMethod.class)) .transform(withModifiers(SynchronizationState.PLAIN, Visibility.PUBLIC)) .attribute(INCLUDING_RECEIVER) .method(isHashCode()) .intercept(to(MockMethodInterceptor.ForHashCode.class)) .method(isEquals()) .intercept(to(MockMethodInterceptor.ForEquals.class)) .serialVersionUid(42L) .defineField("mockitoInterceptor", MockMethodInterceptor.class, PRIVATE) .implement(MockAccess.class) .intercept(FieldAccessor.ofBeanProperty()); Copie les annotations de la méthode
  90. 184.

    DynamicType.Builder<T> builder = byteBuddy.subclass(features.mockedType) .name(nameFor(features.mockedType)) .ignoreAlso(isGroovyMethod()) .annotateType(features.mockedType.getAnnotations()) .implement(new ArrayList<Type>(features.interfaces)) .method(matcher)

    .intercept(to(DispatcherDefaultingToRealMethod.class)) .transform(withModifiers(SynchronizationState.PLAIN, Visibility.PUBLIC)) .attribute(INCLUDING_RECEIVER) .method(isHashCode()) .intercept(to(MockMethodInterceptor.ForHashCode.class)) .method(isEquals()) .intercept(to(MockMethodInterceptor.ForEquals.class)) .serialVersionUid(42L) .defineField("mockitoInterceptor", MockMethodInterceptor.class, PRIVATE) .implement(MockAccess.class) .intercept(FieldAccessor.ofBeanProperty()); hashCode / equals ne sont pas mockable
  91. 185.

    DynamicType.Builder<T> builder = byteBuddy.subclass(features.mockedType) .name(nameFor(features.mockedType)) .ignoreAlso(isGroovyMethod()) .annotateType(features.mockedType.getAnnotations()) .implement(new ArrayList<Type>(features.interfaces)) .method(matcher)

    .intercept(to(DispatcherDefaultingToRealMethod.class)) .transform(withModifiers(SynchronizationState.PLAIN, Visibility.PUBLIC)) .attribute(INCLUDING_RECEIVER) .method(isHashCode()) .intercept(to(MockMethodInterceptor.ForHashCode.class)) .method(isEquals()) .intercept(to(MockMethodInterceptor.ForEquals.class)) .serialVersionUid(42L) .defineField("mockitoInterceptor", MockMethodInterceptor.class, PRIVATE) .implement(MockAccess.class) .intercept(FieldAccessor.ofBeanProperty()); La réponse à la grande question
  92. 186.

    DynamicType.Builder<T> builder = byteBuddy.subclass(features.mockedType) .name(nameFor(features.mockedType)) .ignoreAlso(isGroovyMethod()) .annotateType(features.mockedType.getAnnotations()) .implement(new ArrayList<Type>(features.interfaces)) .method(matcher)

    .intercept(to(DispatcherDefaultingToRealMethod.class)) .transform(withModifiers(SynchronizationState.PLAIN, Visibility.PUBLIC)) .attribute(INCLUDING_RECEIVER) .method(isHashCode()) .intercept(to(MockMethodInterceptor.ForHashCode.class)) .method(isEquals()) .intercept(to(MockMethodInterceptor.ForEquals.class)) .serialVersionUid(42L) .defineField("mockitoInterceptor", MockMethodInterceptor.class, PRIVATE) .implement(MockAccess.class) .intercept(FieldAccessor.ofBeanProperty()); Champs et accesseurs de l’intercepteur mockito
  93. 188.

    public static class DispatcherDefaultingToRealMethod { @SuppressWarnings("unused") @RuntimeType @BindingPriority(BindingPriority.DEFAULT * 2)

    public static Object interceptSuperCallable(@This Object mock, @FieldValue("mockitoInterceptor") MockMethodInterceptor interceptor, @Origin Method invokedMethod, @AllArguments Object[] arguments, @SuperCall(serializableProxy= true) Callable<?> superCall) throws Throwable { if (interceptor == null) { return superCall.call(); } return interceptor.doIntercept( mock, invokedMethod, arguments, new InterceptedInvocation.SuperMethod.FromCallable(superCall) ); } @SuppressWarnings("unused") @RuntimeType public static Object interceptAbstract(@This Object mock, @FieldValue("mockitoInterceptor") MockMethodInterceptor interceptor, @StubValue Object stubValue, @Origin Method invokedMethod, @AllArguments Object[] arguments) throws Throwable { if (interceptor == null) { return stubValue;
  94. 189.

    public static class DispatcherDefaultingToRealMethod { @SuppressWarnings("unused") @RuntimeType @BindingPriority(BindingPriority.DEFAULT * 2)

    public static Object interceptSuperCallable(@This Object mock, @FieldValue("mockitoInterceptor") MockMethodInterceptor interceptor, @Origin Method invokedMethod, @AllArguments Object[] arguments, @SuperCall(serializableProxy= true) Callable<?> superCall) throws Throwable { if (interceptor == null) { return superCall.call(); } return interceptor.doIntercept( mock, invokedMethod, arguments, new InterceptedInvocation.SuperMethod.FromCallable(superCall) ); } @SuppressWarnings("unused") @RuntimeType public static Object interceptAbstract(@This Object mock, @FieldValue("mockitoInterceptor") MockMethodInterceptor interceptor, @StubValue Object stubValue, @Origin Method invokedMethod, @AllArguments Object[] arguments) throws Throwable { if (interceptor == null) { Appelé lorsqu’une invocation à lieu
  95. 190.

    public static class DispatcherDefaultingToRealMethod { @SuppressWarnings("unused") @RuntimeType @BindingPriority(BindingPriority.DEFAULT * 2)

    public static Object interceptSuperCallable(@This Object mock, @FieldValue("mockitoInterceptor") MockMethodInterceptor intercep @Origin Method invokedMethod, @AllArguments Object[] arguments, @SuperCall(serializableProxy= true) Callable<?> superCall) thro Throwable { if (interceptor == null) { return superCall.call(); } return interceptor.doIntercept( mock, invokedMethod, arguments, new InterceptedInvocation.SuperMethod.FromCallable(superCall) ); } @SuppressWarnings("unused") @RuntimeType public static Object interceptAbstract(@This Object mock, @FieldValue("mockitoInterceptor") MockMethodInterceptor interceptor, @StubValue Object stubValue, Indique à byte-buddy les éléments qui nous intéressent
  96. 191.

    public static class DispatcherDefaultingToRealMethod { @SuppressWarnings("unused") @RuntimeType @BindingPriority(BindingPriority.DEFAULT * 2)

    public static Object interceptSuperCallable(@This Object mock, @FieldValue("mockitoInterceptor") MockMethodInterceptor interceptor, @Origin Method invokedMethod, @AllArguments Object[] arguments, @SuperCall(serializableProxy= true) Callable<?> superCall) throws Throwable { if (interceptor == null) { return superCall.call(); } return interceptor.doIntercept( mock, invokedMethod, arguments, new InterceptedInvocation.SuperMethod.FromCallable(superCall) ); } @SuppressWarnings("unused") @RuntimeType public static Object interceptAbstract(@This Object mock, @FieldValue("mockitoInterceptor") MockMethodInterceptor interceptor, @StubValue Object stubValue, @Origin Method invokedMethod, @AllArguments Object[] arguments) throws Throwable { Garde, appelle la méthode concrète de l’objet
  97. 192.

    public static class DispatcherDefaultingToRealMethod { @SuppressWarnings("unused") @RuntimeType @BindingPriority(BindingPriority.DEFAULT * 2)

    public static Object interceptSuperCallable(@This Object mock, @FieldValue("mockitoInterceptor") MockMethodInterceptor interceptor, @Origin Method invokedMethod, @AllArguments Object[] arguments, @SuperCall(serializableProxy= true) Callable<?> superCall) throws Throwable { if (interceptor == null) { return superCall.call(); } return interceptor.doIntercept( mock, invokedMethod, arguments, new InterceptedInvocation.SuperMethod.FromCallable(superCall) ); } @SuppressWarnings("unused") @RuntimeType public static Object interceptAbstract(@This Object mock, @FieldValue("mockitoInterceptor") MockMethodInterceptor interceptor, @StubValue Object stubValue, Invoque la logique interne de Mockito
  98. 193.

    public static class DispatcherDefaultingToRealMethod { // ... public static Object

    interceptSuperCallable(...) Callable<?> superCall) throws Throwable { ... } @SuppressWarnings("unused") @RuntimeType public static Object interceptAbstract(@This Object mock, @FieldValue("mockitoInterceptor") MockMethodInterceptor interceptor, @StubValue Object stubValue, @Origin Method invokedMethod, @AllArguments Object[] arguments) throws Throwable { if (interceptor == null) { return stubValue; } return interceptor.doIntercept( mock, invokedMethod, arguments, InterceptedInvocation.SuperMethod.IsIllegal.INSTANCE ); } } Callback utilisé pour les méthodes abstraites
  99. 194.

    public static class DispatcherDefaultingToRealMethod { // ... public static Object

    interceptSuperCallable(...) Callable<?> superCall) throws Throwable { ... } @SuppressWarnings("unused") @RuntimeType public static Object interceptAbstract(@This Object mock, @FieldValue("mockitoInterceptor") MockMethodInterceptor interceptor, @StubValue Object stubValue, @Origin Method invokedMethod, @AllArguments Object[] arguments) throws Throwable { if (interceptor == null) { return stubValue; } return interceptor.doIntercept( mock, invokedMethod, arguments, InterceptedInvocation.SuperMethod.IsIllegal.INSTANCE ); } } Invoque la logique interne de Mockito
  100. 208.
  101. 217.

    static { try { try { instrumentation = ByteBuddyAgent.install(); if

    (!instrumentation.isRetransformClassesSupported()) { throw new IllegalStateException(...); } JarFile boot = createMockitoMethodDispatcherBootstrapJar(); instrumentation.appendToBootstrapClassLoaderSearch(boot); checkBootstrapJarInjection(); } catch (IOException ioe) { throw new IllegalStateException(..., ioe); } } catch (Throwable throwable) { instrumentation = null; initializationError = throwable; } INSTRUMENTATION = instrumentation; INITIALIZATION_ERROR = initializationError;
  102. 218.

    static { try { try { instrumentation = ByteBuddyAgent.install(); if

    (!instrumentation.isRetransformClassesSupported()) { throw new IllegalStateException(...); } JarFile boot = createMockitoMethodDispatcherBootstrapJar(); instrumentation.appendToBootstrapClassLoaderSearch(boot); checkBootstrapJarInjection(); } catch (IOException ioe) { throw new IllegalStateException(..., ioe); } } catch (Throwable throwable) { instrumentation = null; initializationError = throwable; } INSTRUMENTATION = instrumentation; INITIALIZATION_ERROR = initializationError; Installation de l’agent
  103. 219.

    static { try { try { instrumentation = ByteBuddyAgent.install(); if

    (!instrumentation.isRetransformClassesSupported()) { throw new IllegalStateException(...); } JarFile boot = createMockitoMethodDispatcherBootstrapJar(); instrumentation.appendToBootstrapClassLoaderSearch(boot); checkBootstrapJarInjection(); } catch (IOException ioe) { throw new IllegalStateException(..., ioe); } } catch (Throwable throwable) { instrumentation = null; initializationError = throwable; } INSTRUMENTATION = instrumentation; INITIALIZATION_ERROR = initializationError; Injecte le dispatcher mockito sur le classpath de bootstrap de la VM
  104. 221.

    JVM C mock = mock(C.class); Classe finale Agent mockito Transforme

    / instrumente la classe Indique à l’agent de modifier C
  105. 222.

    JVM C mock = mock(C.class); Classe finale Agent mockito Ajoute

    l’intercepteur mockito dans la classe C
  106. 223.

    @Override public <T> Class<? extends T> mockClass(MockFeatures<T> features) { boolean

    subclassingRequired = !features.interfaces.isEmpty() || features.serializableMode != SerializableMode.NONE || Modifier.isAbstract(features.mockedType.getModifiers()); checkSupportedCombination(subclassingRequired, features); synchronized (this) { triggerRetransformation(features); } return subclassingRequired ? subclassEngine.mockClass(features) : features.mockedType; }
  107. 224.

    @Override public <T> Class<? extends T> mockClass(MockFeatures<T> features) { boolean

    subclassingRequired = !features.interfaces.isEmpty() || features.serializableMode != SerializableMode.NONE || Modifier.isAbstract(features.mockedType.getModifiers()); checkSupportedCombination(subclassingRequired, features); synchronized (this) { triggerRetransformation(features); } return subclassingRequired ? subclassEngine.mockClass(features) : features.mockedType; } Certaines fonctionnalités de mockito ne fonctionnent pas dans ce mode.
  108. 225.

    @Override public <T> Class<? extends T> mockClass(MockFeatures<T> features) { boolean

    subclassingRequired = !features.interfaces.isEmpty() || features.serializableMode != SerializableMode.NONE || Modifier.isAbstract(features.mockedType.getModifiers()); checkSupportedCombination(subclassingRequired, features); synchronized (this) { triggerRetransformation(features); } return subclassingRequired ? subclassEngine.mockClass(features) : features.mockedType; } Instrumente la classe
  109. 226.

    @Override public <T> Class<? extends T> mockClass(MockFeatures<T> features) { boolean

    subclassingRequired = !features.interfaces.isEmpty() || features.serializableMode != SerializableMode.NONE || Modifier.isAbstract(features.mockedType.getModifiers()); checkSupportedCombination(subclassingRequired, features); synchronized (this) { triggerRetransformation(features); } return subclassingRequired ? subclassEngine.mockClass(features) : features.mockedType; } Invoque instrumentation.retransformClasses(types);
  110. 227.

    @Override public <T> Class<? extends T> mockClass(MockFeatures<T> features) { boolean

    subclassingRequired = !features.interfaces.isEmpty() || features.serializableMode != SerializableMode.NONE || Modifier.isAbstract(features.mockedType.getModifiers()); checkSupportedCombination(subclassingRequired, features); synchronized (this) { triggerRetransformation(features); } return subclassingRequired ? subclassEngine.mockClass(features) : features.mockedType; } Si la classe n’est pas finale : créé une sous-classe / implémentation
  111. 228.

    @Override public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain

    protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { if (classBeingRedefined == null || !mocked.contains(classBeingRedefined) || EXCLUDES.contains(classBeingRedefined)) { return null; } else { try { return byteBuddy.redefine(classBeingRedefined, ClassFileLocator.Simple.of(classBeingRedefined.getName(), classfileBuffer)) .visit(new ParameterWritingVisitorWrapper(classBeingRedefined)) .visit(Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.class).on(isVirtual() .and(not(isBridge().or(isHashCode()).or(isEquals()).or(isDefaultFinalizer()))) .and(not(isDeclaredBy(nameStartsWith("java.")).and(isPackagePrivate()))))) .visit(Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.ForHashCode.class).on(isHashCode())) .visit(Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.ForEquals.class).on(isEquals())) .make() .getBytes(); java.lang.instrumentation.ClassFileTransformer
  112. 229.

    @Override public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain

    protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { if (classBeingRedefined == null || !mocked.contains(classBeingRedefined) || EXCLUDES.contains(classBeingRedefined)) { return null; } else { try { return byteBuddy.redefine(classBeingRedefined, ClassFileLocator.Simple.of(classBeingRedefined.getName(), classfileBuffer)) .visit(new ParameterWritingVisitorWrapper(classBeingRedefined)) .visit(Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.class).on(isVirtual() .and(not(isBridge().or(isHashCode()).or(isEquals()).or(isDefaultFinalizer()))) .and(not(isDeclaredBy(nameStartsWith("java.")).and(isPackagePrivate()))))) .visit(Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.ForHashCode.class).on(isHashCode())) .visit(Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.ForEquals.class).on(isEquals())) .make() .getBytes(); } catch (Throwable throwable) { Est-ce que le type doit / peut être modifié ?
  113. 230.

    @Override public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain

    protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { if (classBeingRedefined == null || !mocked.contains(classBeingRedefined) || EXCLUDES.contains(classBeingRedefined)) { return null; } else { try { return byteBuddy.redefine(classBeingRedefined, ClassFileLocator.Simple.of(classBeingRedefined.getName(), classfileBuffer)) .visit(new ParameterWritingVisitorWrapper(classBeingRedefined)) .visit(Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.class).on(isVirtual() .and(not(isBridge().or(isHashCode()).or(isEquals()).or(isDefaultFinalizer()))) .and(not(isDeclaredBy(nameStartsWith("java.")).and(isPackagePrivate()))))) .visit(Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.ForHashCode.class).on(isHashCode())) .visit(Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.ForEquals.class).on(isEquals())) .make() .getBytes(); } catch (Throwable throwable) { Instructions de transformation
  114. 231.

    return byteBuddy.redefine(classBeingRedefined, ClassFileLocator.Simple.of(classBeingRedefined.getName(), classfileBuffer)) .visit(new ParameterWritingVisitorWrapper(classBeingRedefined)) .visit(Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.class).on(isVirtual()

    .and(not(isBridge().or(isHashCode()) .or(isEquals()) .or(isDefaultFinalizer()))) .and(not(isDeclaredBy(nameStartsWith("java.")) .and(isPackagePrivate()))))) .visit(Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.ForHashCode.class).on(isHashCode())) .visit(Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.ForEquals.class).on(isEquals())) .make() .getBytes(); Indique à l’agent byte-buddy ou trouver le bytecode de la classe à modifier
  115. 232.

    return byteBuddy.redefine(classBeingRedefined, ClassFileLocator.Simple.of(classBeingRedefined.getName(), classfileBuffer)) .visit(new ParameterWritingVisitorWrapper(classBeingRedefined)) .visit(Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.class).on(isVirtual()

    .and(not(isBridge().or(isHashCode()) .or(isEquals()) .or(isDefaultFinalizer()))) .and(not(isDeclaredBy(nameStartsWith("java.")) .and(isPackagePrivate()))))) .visit(Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.ForHashCode.class).on(isHashCode())) .visit(Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.ForEquals.class).on(isEquals())) .make() .getBytes(); API basé sur des visiteurs, comme ASM
  116. 233.

    return byteBuddy.redefine(classBeingRedefined, ClassFileLocator.Simple.of(classBeingRedefined.getName(), classfileBuffer)) .visit(new ParameterWritingVisitorWrapper(classBeingRedefined)) .visit(Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.class).on(isVirtual()

    .and(not(isBridge().or(isHashCode()) .or(isEquals()) .or(isDefaultFinalizer()))) .and(not(isDeclaredBy(nameStartsWith("java.")) .and(isPackagePrivate()))))) .visit(Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.ForHashCode.class).on(isHashCode())) .visit(Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.ForEquals.class).on(isEquals())) .make() .getBytes(); Ré-insère le nom des paramètres Java 8 : -parameters
  117. 234.

    return byteBuddy.redefine(classBeingRedefined, ClassFileLocator.Simple.of(classBeingRedefined.getName(), classfileBuffer)) .visit(new ParameterWritingVisitorWrapper(classBeingRedefined)) .visit(Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.class).on(isVirtual()

    .and(not(isBridge().or(isHashCode()) .or(isEquals()) .or(isDefaultFinalizer()))) .and(not(isDeclaredBy(nameStartsWith("java.")) .and(isPackagePrivate()))))) .visit(Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.ForHashCode.class).on(isHashCode())) .visit(Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.ForEquals.class).on(isEquals())) .make() .getBytes(); Instrumente les méthodes mockables
  118. 235.

    return byteBuddy.redefine(classBeingRedefined, ClassFileLocator.Simple.of(classBeingRedefined.getName(), classfileBuffer)) .visit(new ParameterWritingVisitorWrapper(classBeingRedefined)) .visit(Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.class).on(isVirtual()

    .and(not(isBridge().or(isHashCode()) .or(isEquals()) .or(isDefaultFinalizer()))) .and(not(isDeclaredBy(nameStartsWith("java.")) .and(isPackagePrivate()))))) .visit(Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.ForHashCode.class).on(isHashCode())) .visit(Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.ForEquals.class).on(isEquals())) .make() .getBytes(); Donc pas • le constructeur • les méthodes privées hashcode / equals • les bridges … entre autres
  119. 236.

    return byteBuddy.redefine(classBeingRedefined, ClassFileLocator.Simple.of(classBeingRedefined.getName(), classfileBuffer)) .visit(new ParameterWritingVisitorWrapper(classBeingRedefined)) .visit(Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.class).on(isVirtual()

    .and(not(isBridge().or(isHashCode()) .or(isEquals()) .or(isDefaultFinalizer()))) .and(not(isDeclaredBy(nameStartsWith("java.")) .and(isPackagePrivate()))))) .visit(Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.ForHashCode.class).on(isHashCode())) .visit(Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.ForEquals.class).on(isEquals())) .make() .getBytes(); Instrumente de manière spécifique les méthodes hashcode / equals
  120. 237.

    return byteBuddy.redefine(classBeingRedefined, ClassFileLocator.Simple.of(classBeingRedefined.getName(), classfileBuffer)) .visit(new ParameterWritingVisitorWrapper(classBeingRedefined)) .visit(Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.class).on(isVirtual()

    .and(not(isBridge().or(isHashCode()) .or(isEquals()) .or(isDefaultFinalizer()))) .and(not(isDeclaredBy(nameStartsWith("java.")) .and(isPackagePrivate()))))) .visit(Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.ForHashCode.class).on(isHashCode())) .visit(Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.ForEquals.class).on(isEquals())) .make() .getBytes(); Renvoie le bytecode de la classe instrumentée
  121. 238.

    Qui suis-je ? Back to basics Mockito 2 Nouvelles features

    Mockito 2 Changements internes Release delivery continuum Mockito 3 What’s next
  122. 256.

    git push upstream ✓ Not skipped ✓ Releasable branch ?

    ✓ Not a PR ✓ Previous and current jar are different [release/2.x] $ release/2.x
  123. 258.

    ✓ Not skipped ✓ Releasable branch ? ✓ Not a

    PR ✓ Previous and current jar are different release/2.x PR #73 → release/2.x
  124. 272.

    Qui suis-je ? Back to basics Mockito 2 Nouvelles features

    Mockito 2 Changements internes Mockito 3 What’s next Release delivery continuum
  125. 279.

    Qui suis-je ? Back to basics Mockito 2 Nouvelles features

    Mockito 2 Changements internes Mockito 3 What’s next Release delivery continuum
  126. 282.
  127. 283.

    1. Qui suis-je ? 2. Back to basics a. Do

    you know mockito ? yes / no b. Do you know what is a mock ? yes / no 3. Nouvelles features de Mockito 2 a. Premier support de Java 8 b. Meilleur support des generics c. Qualité / Strict mocking d. API entre Java 6 et Java 8 e. Mockito.framework() / listeners f. Plugins g. Android support h. Classes finales i. Kotlin 4. Changements internes de Mockito 2 a. Bytebuddy (incompatibilité avec PowerMock) b. Mocking des classes finales 5. Release model a. Continuous delivery continuum 6. Pour Mockito 3 a. Extensions du support Java 8 b. Java 9 ready, dans les faits dépends de ASM6 c. Simplicity d. BDD api only ?
  128. 284.

    Qui suis-je ? Back to basics Mockito 2 Nouvelles features

    Mockito 2 Changements internes Release model Mockito 3 What’s next
  129. 285.
  130. 288.

    Mockito / BDDMockito @Mock / @Spy / @InjectMocks ArgumentMatchers /

    AdditionalMatchers Answers / AdditionalAnswers
  131. 299.

    Mockito.framework().addListener(new MockCreationListener() { @Override public void onMockCreated(Object mock, MockCreationSettings settings)

    { System.out.println("new mock created '" + mock + "'"); } }); ... Mockito.mock(AwesomeType.class);
  132. 306.

    public class ScreamOnSerializableMock implements TestRule { @Override public Statement apply(Statement

    base, Description description) { return new Statement() { @Override public void evaluate() throws Throwable { base.evaluate(); } }; } }
  133. 307.

    public class ScreamOnSerializableMock implements TestRule { @Override public Statement apply(Statement

    base, Description description) { MockCreationListener listener = new SerializableMockCreationListener(); return new Statement() { @Override public void evaluate() throws Throwable { base.evaluate(); } }; } }
  134. 308.

    public class ScreamOnSerializableMock implements TestRule { @Override public Statement apply(Statement

    base, Description description) { MockCreationListener listener = new SerializableMockCreationListener(); return new Statement() { @Override public void evaluate() throws Throwable { Mockito.framework().addListener(listener); base.evaluate(); } }; } }
  135. 309.

    public class ScreamOnSerializableMock implements TestRule { @Override public Statement apply(Statement

    base, Description description) { MockCreationListener listener = new SerializableMockCreationListener(); return new Statement() { @Override public void evaluate() throws Throwable { Mockito.framework().addListener(listener); base.evaluate(); } }; } } Ajoute le listener pour la méthode de test
  136. 310.

    public class ScreamOnSerializableMock implements TestRule { @Override public Statement apply(Statement

    base, Description description) { MockCreationListener listener = new SerializableMockCreationListener(); return new Statement() { @Override public void evaluate() throws Throwable { try { Mockito.framework().addListener(listener); base.evaluate(); } finally { Mockito.framework().removeListener(listener); } } }; } } Important supprimer le listener
  137. 314.

    class SerializableMockCreationListener implements MockCreationListener { @Override public void onMockCreated(Object mock,

    MockCreationSettings settings) { if(settings.isSerializable()) { String msg = format("serializable mock created '%s', with mode=%s", mock, settings.getSerializableMode()); System.out.println(msg); throw new ProgrammerError(msg); } } }
  138. 318.
  139. 323.

    class PassengerNameRecordTest { @Mock val pnr = PassengerNameRecord() @Rule @JvmField

    public val rulez = MockitoJUnit.rule(); @Test fun should_behave_like_that() { ... } }
  140. 326.
  141. 330.

    Enhancer enhancer = new Enhancer(); Class<?>[] allMockedTypes = prepend(mockedType, interfaces);

    enhancer.setClassLoader(SearchingClassLoader.combineLoadersOf(allMockedTypes)); enhancer.setUseFactory(true); if (mockedType.isInterface()) { enhancer.setSuperclass(Object.class); enhancer.setInterfaces(allMockedTypes); } else { enhancer.setSuperclass(mockedType); enhancer.setInterfaces(interfaces); } enhancer.setCallbackTypes(new Class[]{MethodInterceptor.class, NoOp.class}); enhancer.setCallbackFilter(IGNORE_BRIDGE_METHODS); if (mockedType.getSigners() != null) { enhancer.setNamingPolicy(NAMING_POLICY_THAT_ALLOWS_IMPOSTERISATION_OF_CLASSES_IN_SIGNED_PACKAGES); } else { enhancer.setNamingPolicy(MockitoNamingPolicy.INSTANCE); } enhancer.setSerialVersionUID(42L); try { return enhancer.createClass(); } catch (CodeGenerationException e) { // propagate with meaningful message } Configuration de CGLIB pour créer la classe du mock
  142. 331.

    Enhancer enhancer = new Enhancer(); Class<?>[] allMockedTypes = prepend(mockedType, interfaces);

    enhancer.setClassLoader(SearchingClassLoader.combineLoadersOf(allMockedTypes)); enhancer.setUseFactory(true); if (mockedType.isInterface()) { enhancer.setSuperclass(Object.class); enhancer.setInterfaces(allMockedTypes); } else { enhancer.setSuperclass(mockedType); enhancer.setInterfaces(interfaces); } enhancer.setCallbackTypes(new Class[]{MethodInterceptor.class, NoOp.class}); enhancer.setCallbackFilter(IGNORE_BRIDGE_METHODS); if (mockedType.getSigners() != null) { enhancer.setNamingPolicy(NAMING_POLICY_THAT_ALLOWS_IMPOSTERISATION_OF_CLASSES_IN_SIGNED_PACKAGES); } else { enhancer.setNamingPolicy(MockitoNamingPolicy.INSTANCE); } enhancer.setSerialVersionUID(42L); try { return enhancer.createClass(); } catch (CodeGenerationException e) { // propagate with meaningful message } Instance du créateur de classe de CGLIB
  143. 332.

    Enhancer enhancer = new Enhancer(); Class<?>[] allMockedTypes = prepend(mockedType, interfaces);

    enhancer.setClassLoader(SearchingClassLoader.combineLoadersOf(allMockedTypes)); enhancer.setUseFactory(true); if (mockedType.isInterface()) { enhancer.setSuperclass(Object.class); enhancer.setInterfaces(allMockedTypes); } else { enhancer.setSuperclass(mockedType); enhancer.setInterfaces(interfaces); } enhancer.setCallbackTypes(new Class[]{MethodInterceptor.class, NoOp.class}); enhancer.setCallbackFilter(IGNORE_BRIDGE_METHODS); if (mockedType.getSigners() != null) { enhancer.setNamingPolicy(NAMING_POLICY_THAT_ALLOWS_IMPOSTERISATION_OF_CLASSES_IN_SIGNED_PACKAGES); } else { enhancer.setNamingPolicy(MockitoNamingPolicy.INSTANCE); } enhancer.setSerialVersionUID(42L); try { return enhancer.createClass(); } catch (CodeGenerationException e) { // propagate with meaningful message } Mocked type + extra interfaces
  144. 333.

    Enhancer enhancer = new Enhancer(); Class<?>[] allMockedTypes = prepend(mockedType, interfaces);

    enhancer.setClassLoader(SearchingClassLoader.combineLoadersOf(allMockedTypes)); enhancer.setUseFactory(true); if (mockedType.isInterface()) { enhancer.setSuperclass(Object.class); enhancer.setInterfaces(allMockedTypes); } else { enhancer.setSuperclass(mockedType); enhancer.setInterfaces(interfaces); } enhancer.setCallbackTypes(new Class[]{MethodInterceptor.class, NoOp.class}); enhancer.setCallbackFilter(IGNORE_BRIDGE_METHODS); if (mockedType.getSigners() != null) { enhancer.setNamingPolicy(NAMING_POLICY_THAT_ALLOWS_IMPOSTERISATION_OF_CLASSES_IN_SIGNED_PACKAGES); } else { enhancer.setNamingPolicy(MockitoNamingPolicy.INSTANCE); } enhancer.setSerialVersionUID(42L); try { return enhancer.createClass(); } catch (CodeGenerationException e) { // propagate with meaningful message } Classloader chargé trouvé les bon classloader pour chaque type
  145. 334.

    Enhancer enhancer = new Enhancer(); Class<?>[] allMockedTypes = prepend(mockedType, interfaces);

    enhancer.setClassLoader(SearchingClassLoader.combineLoadersOf(allMockedTypes)); enhancer.setUseFactory(true); if (mockedType.isInterface()) { enhancer.setSuperclass(Object.class); enhancer.setInterfaces(allMockedTypes); } else { enhancer.setSuperclass(mockedType); enhancer.setInterfaces(interfaces); } enhancer.setCallbackTypes(new Class[]{MethodInterceptor.class, NoOp.class}); enhancer.setCallbackFilter(IGNORE_BRIDGE_METHODS); if (mockedType.getSigners() != null) { enhancer.setNamingPolicy(NAMING_POLICY_THAT_ALLOWS_IMPOSTERISATION_OF_CLASSES_IN_SIGNED_PACKAGES); } else { enhancer.setNamingPolicy(MockitoNamingPolicy.INSTANCE); } enhancer.setSerialVersionUID(42L); try { return enhancer.createClass(); } catch (CodeGenerationException e) { // propagate with meaningful message } Équivalent de @PostConstruct
  146. 335.

    Enhancer enhancer = new Enhancer(); Class<?>[] allMockedTypes = prepend(mockedType, interfaces);

    enhancer.setClassLoader(SearchingClassLoader.combineLoadersOf(allMockedTypes)); enhancer.setUseFactory(true); if (mockedType.isInterface()) { enhancer.setSuperclass(Object.class); enhancer.setInterfaces(allMockedTypes); } else { enhancer.setSuperclass(mockedType); enhancer.setInterfaces(interfaces); } enhancer.setCallbackTypes(new Class[]{MethodInterceptor.class, NoOp.class}); enhancer.setCallbackFilter(IGNORE_BRIDGE_METHODS); if (mockedType.getSigners() != null) { enhancer.setNamingPolicy(NAMING_POLICY_THAT_ALLOWS_IMPOSTERISATION_OF_CLASSES_IN_SIGNED_PACKAGES); } else { enhancer.setNamingPolicy(MockitoNamingPolicy.INSTANCE); } enhancer.setSerialVersionUID(42L); try { Hack pour gérer les mocks de classes ou les mocks d’interfaces
  147. 336.

    Enhancer enhancer = new Enhancer(); Class<?>[] allMockedTypes = prepend(mockedType, interfaces);

    enhancer.setClassLoader(SearchingClassLoader.combineLoadersOf(allMockedTypes)); enhancer.setUseFactory(true); if (mockedType.isInterface()) { enhancer.setSuperclass(Object.class); enhancer.setInterfaces(allMockedTypes); } else { enhancer.setSuperclass(mockedType); enhancer.setInterfaces(interfaces); } enhancer.setCallbackTypes(new Class[]{MethodInterceptor.class, NoOp.class}); enhancer.setCallbackFilter(IGNORE_BRIDGE_METHODS); if (mockedType.getSigners() != null) { enhancer.setNamingPolicy(NAMING_POLICY_THAT_ALLOWS_IMPOSTERISATION_OF_CLASSES_IN_SIGNED_PACKAGES); } else { enhancer.setNamingPolicy(MockitoNamingPolicy.INSTANCE); } enhancer.setSerialVersionUID(42L); try { return enhancer.createClass(); } catch (CodeGenerationException e) { // propagate with meaningful message } Type du callback que Mockito doit implémenter Type de callback NoOp
  148. 337.

    Enhancer enhancer = new Enhancer(); Class<?>[] allMockedTypes = prepend(mockedType, interfaces);

    enhancer.setClassLoader(SearchingClassLoader.combineLoadersOf(allMockedTypes)); enhancer.setUseFactory(true); if (mockedType.isInterface()) { enhancer.setSuperclass(Object.class); enhancer.setInterfaces(allMockedTypes); } else { enhancer.setSuperclass(mockedType); enhancer.setInterfaces(interfaces); } enhancer.setCallbackTypes(new Class[]{MethodInterceptor.class, NoOp.class}); enhancer.setCallbackFilter(IGNORE_BRIDGE_METHODS); if (mockedType.getSigners() != null) { enhancer.setNamingPolicy(NAMING_POLICY_THAT_ALLOWS_IMPOSTERISATION_OF_CLASSES_IN_SIGNED_PACKAGES); } else { enhancer.setNamingPolicy(MockitoNamingPolicy.INSTANCE); } enhancer.setSerialVersionUID(42L); try { return enhancer.createClass(); } catch (CodeGenerationException e) { // propagate with meaningful message } CGLIB ne gère pas les bridge méthodes
  149. 338.

    Enhancer enhancer = new Enhancer(); Class<?>[] allMockedTypes = prepend(mockedType, interfaces);

    enhancer.setClassLoader(SearchingClassLoader.combineLoadersOf(allMockedTypes)); enhancer.setUseFactory(true); if (mockedType.isInterface()) { enhancer.setSuperclass(Object.class); enhancer.setInterfaces(allMockedTypes); } else { enhancer.setSuperclass(mockedType); enhancer.setInterfaces(interfaces); } enhancer.setCallbackTypes(new Class[]{MethodInterceptor.class, NoOp.class}); enhancer.setCallbackFilter(IGNORE_BRIDGE_METHODS); if (mockedType.getSigners() != null) { enhancer.setNamingPolicy( NAMING_POLICY_THAT_ALLOWS_IMPOSTERISATION_OF_CLASSES_IN_SIGNED_PACKAGES); } else { enhancer.setNamingPolicy(MockitoNamingPolicy.INSTANCE); } enhancer.setSerialVersionUID(42L); try { Gestion du nommage pour les packages signés. Par exemple java.util
  150. 339.

    Enhancer enhancer = new Enhancer(); Class<?>[] allMockedTypes = prepend(mockedType, interfaces);

    enhancer.setClassLoader(SearchingClassLoader.combineLoadersOf(allMockedTypes)); enhancer.setUseFactory(true); if (mockedType.isInterface()) { enhancer.setSuperclass(Object.class); enhancer.setInterfaces(allMockedTypes); } else { enhancer.setSuperclass(mockedType); enhancer.setInterfaces(interfaces); } enhancer.setCallbackTypes(new Class[]{MethodInterceptor.class, NoOp.class}); enhancer.setCallbackFilter(IGNORE_BRIDGE_METHODS); if (mockedType.getSigners() != null) { enhancer.setNamingPolicy( NAMING_POLICY_THAT_ALLOWS_IMPOSTERISATION_OF_CLASSES_IN_SIGNED_PACKAGES); } else { enhancer.setNamingPolicy(MockitoNamingPolicy.INSTANCE); } enhancer.setSerialVersionUID(42L); try { Le nom de la classe contiendra EnhancedByMockitoWithCGLIB
  151. 340.

    Enhancer enhancer = new Enhancer(); Class<?>[] allMockedTypes = prepend(mockedType, interfaces);

    enhancer.setClassLoader(SearchingClassLoader.combineLoadersOf(allMockedTypes)); enhancer.setUseFactory(true); if (mockedType.isInterface()) { enhancer.setSuperclass(Object.class); enhancer.setInterfaces(allMockedTypes); } else { enhancer.setSuperclass(mockedType); enhancer.setInterfaces(interfaces); } enhancer.setCallbackTypes(new Class[]{MethodInterceptor.class, NoOp.class}); enhancer.setCallbackFilter(IGNORE_BRIDGE_METHODS); if (mockedType.getSigners() != null) { enhancer.setNamingPolicy(NAMING_POLICY_THAT_ALLOWS_IMPOSTERISATION_OF_CLASSES_IN_SIGNED_PACKAGES); } else { enhancer.setNamingPolicy(MockitoNamingPolicy.INSTANCE); } enhancer.setSerialVersionUID(42L); try { return enhancer.createClass(); } catch (CodeGenerationException e) { // propagate with meaningful message } Génère le bytecode et charge la classe dans SearchingClassLoader