[JAVA] Utilisation correcte de Mockito et PowerMock

J'ai essayé d'organiser la bonne utilisation de Mockito et PowerMock lors de la simulation de diverses méthodes lors des tests avec JUnit avec Spring Boot.

Paramètres requis pour les tests

build.gradle


dependencies {
    compile("org.springframework.boot:spring-boot-starter-web")
    testCompile('org.springframework.boot:spring-boot-starter-test')
    testCompile group: 'org.powermock', name: 'powermock-api-mockito', version: '1.6.6'
    testCompile group: 'org.powermock', name: 'powermock-module-junit4', version: '1.6.6'
}

Insérez simplement spring-boot-starter-test et vous pourrez utiliser les deux bibliothèques suivantes. La version est ** spring-boot-gradle-plugin: 1.5.2.RELEASE **.

Ajoutez un paramètre pour utiliser la simulation de puissance qui sera utilisée plus tard.


Classe utilisée pour l'explication

Classe à tester

TestTargetClass.java


@Component
public class TestTargetClass {
  @Autowired
  private TestSubClass testSubClass;

  private String private_method() {
    return "private_method called " + private_sub();
  }

  private String private_sub() {
    return "private_sub";
  }

  public String public_method() {
    return "public_method called " + public_sub();
  }

  public String public_sub() {
    return "public_sub";
  }

  public String public_method_call_private_method() {
    return "public_method called " + private_sub();
  }

  public static String static_method() {
    return "static_method";
  }

  public String public_subclass_public_method() {
    return "public_subclass_method called " + testSubClass.sub_public_method();
  }

  public String public_subclass_private_method() {
    return "public_subclass_method called " + testSubClass.sub_public_method_call_private_method();
  }
}

Sous-classe à tester (sous-classe DI de la classe parente)

TestSubClass.java


@Component
public class TestSubClass {

  public String public_field = "public_field";
  private String private_field = "private_field";

  private String sub_private_method() {
    return "subclass_private_method has " + private_field;
  }

  public String sub_public_method() {
    return "subclass_public_method has " + public_field;
  }

  public String sub_public_method_call_private_method() {
    return "subclass_public_method called " + sub_private_method();
  }
}

Premier du test de base

Vous pouvez utiliser Mockito pour la classe de test comme ceci.

RealTest.java


@RunWith(SpringRunner.class)
@SpringBootTest
public class RealTest {
  @Autowired
  private TestTargetClass instance;

  @Test
méthode de test public void() {
    .....
  }
}

Tester le comportement réel des méthodes publiques

Inutile d'écrire, voici le code de test

  @Test
public void peut être testé en appelant des méthodes publiques() {
    assertThat(public_method(), is("public_method called public_sub"));
  }

Tester le comportement réel des méthodes privées

OK si vous utilisez setAccessible avec réflexion

  @Test
public void Peut être testé en appelant des méthodes privées() throws Exception {
    Method method = TestTargetClass.class.getDeclaredMethod("private_method");
    method.setAccessible(true);
    assertThat((String) method.invoke(instance), is("private_method called private_sub"));
  }

Tester le comportement réel des méthodes statiques

Inutile d'écrire, voici le code de test

  @Test
public void Peut être testé en appelant des méthodes statiques() {
    assertThat(TestTargetClass.static_method(), is("static_method"));
  }

Voici le test utilisant la maquette du sujet principal.


Tests qui ne peuvent être effectués qu'avec Mockito

Lorsque vous vous moquez d'une méthode publique

Dans de tels cas, utilisez «Mockito.mock ()».

  @Test
public void Vous pouvez vous moquer des méthodes publiques() {
    TestTargetClass mockInstance = mock(TestTargetClass.class);
    when(mockInstance.public_method()).thenReturn("mocked_public_method");
    assertThat(mockInstance.public_method(), is("mocked_public_method"));
  }

Lors de la moquerie d'une méthode sous-publique appelée à partir d'une méthode publique

Je veux que les méthodes autres que la méthode moqueuse public_sub () fonctionnent comme implémentées, alors utilisez Mockito.spy () dans de tels cas.

  @Test
public void La méthode Sub appelée par la méthode publique peut être simulée avec Spy() {
    TestTargetClass mockInstance = spy(new TestTargetClass());
    when(mockInstance.public_sub()).thenReturn("mocked_public_sub");
    assertThat(mockInstance.public_method(), is("public_method called mocked_public_sub"));
  }

Tests pouvant être effectués avec PowerMock

La classe de test lors de l'utilisation de PowerMock ressemble à ceci

@RunWith(PowerMockRunner.class)
@PrepareForTest({TestTargetClass.class})
public class PowerMockTest {
  @Test
méthode de test public void() {
    .....
  }
}

Méthode privée simulée

Utilisez PowerMockito.mock () et PowerMockito.when (). Aussi, utilisez MemberMatcher.method () pour refléter pour spécifier une méthode privée.

  @Test
Les méthodes publiques void privées peuvent être simulées avec PowerMockito() throws Exception {
    TestTargetClass mockInstance = PowerMockito.mock(TestTargetClass.class);
    PowerMockito.when(mockInstance, MemberMatcher.method(TestTargetClass.class, "private_method"))
                .withNoArguments().thenReturn("mocked_private_method");

    //Utilisez la réflexion pour accéder aux méthodes privées
    Method method = TestTargetClass.class.getDeclaredMethod("private_method");
    method.setAccessible(true);

    assertThat((String) method.invoke(mockInstance), is("mocked_private_method"));
  }

Méthode statique simulée

Utilisez PowerMockito.mockStatic () et PowerMockito.when ().


  @Test
Les méthodes statiques de public void peuvent être simulées avec PowerMockito()() {
    PowerMockito.mockStatic(TestTargetClass.class);
    PowerMockito.when(TestTargetClass.static_method()).thenReturn("mocked_static_method");
    assertThat(TestTargetClass.static_method(), is("mocked_static_method"));
  }

Lors de la simulation d'une sous-méthode privée appelée à partir d'une méthode publique

Je veux que les méthodes autres que la méthode moqueuse private_sub () fonctionnent comme implémentées, utilisez donc PowerMockito.spy () et PowerMockito.when () dans de tels cas. Cela reflète également l'utilisation de MemberMatcher.method () pour spécifier une méthode privée.

  @Test
public void Les méthodes sous-privées appelées à partir de méthodes publiques peuvent être simulées avec spy() throws Exception {
    TestTargetClass mockInstance = PowerMockito.spy(new TestTargetClass());
    PowerMockito.when(mockInstance, MemberMatcher.method(TestTargetClass.class, "private_sub"))
                .withNoArguments().thenReturn("mocked_private_sub");

    assertThat(mockInstance.public_method_call_private_method(),
        is("public_method called mocked_private_sub"));
  }

Lorsque vous vous moquez d'une classe qui est DI dans la classe

On suppose que la classe de service qui est DI dans la classe de contrôleur est simulée. PowerMock est également utilisé à ce moment. DI la classe cible de @ Autowired spécifiée dans la classe spécifiée par @ InjectMocks dans l'annotation @ SpringBootTest. La classe cible de @ Autowired est` PowerMockito.spy () ʻen tant que variable de classe.


La classe de test ressemble à ceci

@RunWith(PowerMockRunner.class)
//Classe cible PowerMock
@PrepareForTest({TestSubClass.class})
@SpringBootTest
public class PowerMockSubclassTest {
  @InjectMocks
  private TestTargetClass instance;
  private TestSubClass testSubClass = PowerMockito.spy(new TestSubClass());

  @Test
méthode de test public void() {
    .....
  }
}

Il semble que vous ne pouvez pas vous moquer même si vous faites ce qui suit au lieu de la variable de classe. ... peut-être Veuillez commenter s'il existe un bon moyen.

  @Test
méthode de test public void() {
     TestSubClass testSubClass = PowerMockito.spy(new TestSubClass());
  }

Mock méthodes publiques des sous-classes

Puisqu'il s'agit en fait d'une méthode publique, la partie où la sous-classe est déclarée dans la classe de test est

private TestSubClass testSubClass = PowerMockito.mock(TestSubClass.class);

C'est bon, mais il ne peut pas être utilisé avec celui utilisant spy () dans le même fichier source, donc je vais l'unifier avec spy (). Utilisez PowerMockito.when ().

  @Test
public void Peut se moquer des méthodes publiques des sous-classes() {
    PowerMockito.when(testSubClass.sub_public_method()).thenReturn("mocked_subclass_public_method");
    assertThat(instance.public_subclass_public_method(),
        is("public_subclass_method called mocked_subclass_public_method"));
  }

Mock la méthode privée de la sous-classe

Utilisez PowerMockito.when (). Cela reflète également l'utilisation de MemberMatcher.method () pour spécifier une méthode privée.

  @Test
public void Peut se moquer des méthodes privées des sous-classes() throws Exception {
    PowerMockito.when(testSubClass, MemberMatcher.method(TestSubClass.class, "sub_private_method"))
        .withNoArguments().thenReturn("mocked_sub_private_method");

    assertThat(instance.public_subclass_private_method(), is(
        "public_subclass_method called subclass_public_method called mocked_sub_private_method"));
  }

Se moquer du champ public d'une sous-classe

Utilisez Whitebox.setInternalState () pour définir une simulation sur un champ de sous-classe.

  @Test
public void Peut se moquer des champs publics des sous-classes() {
    Whitebox.setInternalState(testSubClass, "public_field", "mocked_public_field");
    assertThat(instance.public_subclass_public_method(),
        is("public_subclass_method called subclass_public_method has mocked_public_field"));
  }

Mock les champs privés de la sous-classe

Utilisez Whitebox.setInternalState () pour définir une simulation sur un champ de sous-classe. Identique au réglage dans le domaine public.

  @Test
public void Peut se moquer des champs privés des sous-classes() {
    Whitebox.setInternalState(testSubClass, "private_field", "mocked_private_field");
    assertThat(instance.public_subclass_private_method(), is(
        "public_subclass_method called subclass_public_method called subclass_private_method has mocked_private_field"));
  }

C'est une longue phrase, mais c'est tout.

Recommended Posts

Utilisation correcte de Mockito et PowerMock
Utilisez redirect_to et effectuez un rendu correctement
Utilisation correcte de l'interface et de la classe abstraite
Critères pour utiliser correctement render et redirect_to
[Java8] Utilisation appropriée de Compareable et Comparator du point de vue du tri des employés
(Déterminez en 1 minute) Comment utiliser vide?, Vide? Et présent?
Utilisez-vous l'instruction for après tout? Utilisez-vous l'instruction while? Utilisation correcte des instructions for et while
Utilisation de la classe Date
Aide-mémoire Mockito + PowerMock
Utilisation de polices japonaises et de caractères étrangers dans Jasper Report
Utilisation minimale de Mockito
Jusqu'à l'utilisation de Spring Data et JPA Part 2
Jusqu'à l'utilisation de Spring Data et JPA Part 1
Utilisation correcte de la classe abstraite et de l'interface en Java
Traitement de la date et de l'heure en Ruby. Utilisez correctement la date et l'heure.
Contexte et mécanisme de Fabric-loader
Résumé de FileInputStream et BufferedInputStream
Combinaison de recherche et each_with_index
Jugement de JSONArray et JSONObject
Mock et espionner PowerMock
Utilisez @ValueSource de ParametrisedTest de JUnit5
Opérateur résiduel et puissance (冪 puissance)
Avantages et inconvénients de Java
[Docker-compose] Comment utiliser des volumes de volumes non nommés et nommés. Lier la monture