SpringBoot —— Résumé de la pratique des tests unitaires

Test de l'unité

concept

En programmation informatique, les tests unitaires (en anglais : Unit Testing), également appelés tests de modules, sont un test de l'exactitude des modules de programme (la plus petite unité de conception de logiciels). Une unité de programme est le plus petit composant testable d'une application. En programmation procédurale, une unité est un programme, une fonction, un processus, etc. ; pour la programmation orientée objet, la plus petite unité est une méthode, y compris les méthodes des classes de base (superclasses), des classes abstraites ou des classes dérivées (sous-classes). --Wikipédia

effet

  1. Amélioration de la qualité
    Un test unique peut réduire les bogues potentiels dans une certaine mesure et améliorer la qualité du code. Les tests unitaires résolvent non seulement le problème de couverture, mais couvrent également certains problèmes de gestion des limites et des exceptions dans le bloc de code.
  2. Refactoring
    Le test unique peut accompagner d'autres petits partenaires pour modifier et refactoriser le code à l'avenir, car tant que vous osez changer le code au hasard, le test unique osera signaler une erreur pour vous.
  3. Débogage
    Les tests unitaires sont utiles pour le débogage du code. Nous pouvons nous moquer des classes, méthodes et paramètres dépendants en fonction des besoins, sans véritables appels aux classes et méthodes en aval.
  4. Le test unique CodeReview
    est également un processus d'auto-CodeReview. Tester séparément le flux principal, les branches, les limites et les exceptions des unités fonctionnelles permet de déterminer si la conception logique du code est raisonnable. À l'inverse, incitez-vous à améliorer votre prise de conscience de la qualité du codage. En particulier, une méthode avec des centaines de lignes, lors de l'écriture d'un seul test, vous trouverez cette masse, pourquoi ne pas la démonter ?

boîte noire et blanche

test de la boîte noire

  Le test de boîte noire est également appelé 功能测试ou 数据驱动测试, pendant le processus de test, le programme est considéré comme une boîte noire et la structure de code interne de la boîte ne peut pas être vue.
  Les tests en boîte noire sont principalement basés sur des exigences fonctionnelles pour concevoir des cas de test pour les tests, qui est une méthode de test mise en œuvre depuis l'extérieur du logiciel. Entrez les paramètres plusieurs fois pour tester si le programme est normal ou répond aux attentes.
  La boîte noire ne connaît que la fonction du logiciel (ce qu'elle peut faire), mais ne connaît pas l'implémentation du logiciel (comment il fonctionne).

test de la boîte blanche

  Le test en boîte blanche est également appelé 结构测试ou 逻辑驱动测试, pendant le processus de test, le programme est considéré comme une boîte transparente, et le code et la structure à l'intérieur de la boîte peuvent être vus clairement, de sorte que le testeur comprenne la logique du code du programme .
  Passez les paramètres sous forme de chemins exhaustifs et vérifiez si toutes les structures du code sont normales ou répondent aux attentes. Les tests unitaires sont des tests boîte blanche.
  La boîte blanche connaît l'implémentation du logiciel (comment le faire), et n'a pas besoin de se soucier de la fonction du logiciel (ce qu'il peut faire).

couverture logique

1. Couverture de la déclaration

  Chaque instruction exécutable du programme est exécutée au moins une fois, c'est-à-dire que le cas de test couvre toutes les instructions.

2. Couverture du jugement

  Aussi connu sous le nom de couverture de branche, pour l'expression de décision, vrai ou faux deux jugements vrai et faux, chaque branche du jugement dans le programme est vécue au moins une fois.
  Par exemple, l'expression de décision : a > 0 && b > 0
  concevoir des données de test

a > 0 && b > 0(判定表达式的值为“真”)
a <= 0 && b <= 0(判定表达式的值为“假”)

  Toutes les branches qui satisfont la décision sont couvertes (pour le moment, les branches vraies et fausses sont couvertes).

3. Couverture des conditions

  Pour les conditions dans l'énoncé de jugement, chaque valeur de chaque condition dans chaque jugement dans le programme est satisfaite au moins une fois, pour l'énoncé conditionnel.
  Par exemple, l'expression de décision : a > 0 && b > 0
  concevoir des données de test

a <= 0 && b <= 0(判定表达式的值为“假”)
a > 0 && b <= 0(判定表达式的值为“假”)

  Chaque condition est garantie de prendre une valeur une fois, que la branche soit entièrement couverte ou non (seules les fausses branches sont couvertes à ce moment).

4. Couverture des conditions/jugements

  Dans la condition de jugement, le fait que toutes les conditions possibles soient vraies ou non est exécuté au moins une fois, et les résultats possibles de tous les jugements vrais et faux sont exécutés au moins une fois.
  Par exemple, l'expression de décision : a > 0 && b > 0
  concevoir des données de test

a > 0 && b > 0(判定表达式的值为“真”)
a <= 0 && b <= 0(判定表达式的值为“假”)

5. Couverture combinée des conditions

  Toutes les combinaisons possibles de valeurs conditionnelles sont exécutées au moins une fois.
  Par exemple, l'expression de décision : a > 0 && b > 0
  concevoir des données de test

a > 0 && b > 0(判定表达式的值为“真”)
a <= 0 && b <= 0(判定表达式的值为“假”)
a > 0 && b <= 0(判定表达式的值为“假”)
a <= 0 && b > 0(判定表达式的值为“假”)

  Toutes les combinaisons possibles de conditions dans la décision.

6. Couverture du chemin


  tous les chemins d'exécution possibles.

Introduction au test unique SpringBoot Engineering

dépendances pom

<dependency> 
<groupId>org.springframework.boot</groupId> 
<artifactId>spring-boot-starter-test</artifactId> 
<scope>test</scope> 
</dependency> 

Avis:

  1. La version de dépendance suit généralement la version SpringBoot correspondante et n'a pas besoin d'être spécifiée manuellement.
  2. Cette dépendance introduira automatiquement des dépendances liées :
    JUnit
    Mockito
    Spring Test
    … …

Structure de l'idée

créer un chemin

  Créez src/test au même niveau que src/main et conservez les autres chemins de classe cohérents avec le package principal. (Le chemin peut être créé automatiquement en créant une méthode de raccourci de la classe)

Créer des classes et des méthodes

La méthode de raccourci pour créer une classe correspondant à la classe de test unitaire : il suffit de double-cliquer sur la classe, de cliquer avec le bouton droit de la souris et de sélectionner Aller à Test.

Sélectionnez la méthode à tester, en même temps, vous pouvez sélectionner la version JUnit, etc., cliquez sur OK

Test unique de la couche contrôleur

code sous test

@Slf4j
@RestController
@RequestMapping("/demo")
@Api(value = "DemoController", tags = "Demo管理模块")
public class DemoController implements DemoApi {
    
    
    /**
     * service
     */
    @Autowired
    private DemoService demoService;


    @Override
    @ApiOperation(value = "新增", notes = "新增")
    @PostMapping("/create")
    public Boolean add(@RequestHeader("appCode") String appCode,
                                     @RequestBody DemoDTO demoDTO) {
    
    
        boolean addFlag = demoService.add(demoDTO);
        if (addFlag) {
    
    
            // 刷新资源
          demoService.refreshMap(appCode);
        }
        return addFlag;
    }


    @Override
    @ApiOperation(value = "修改", notes = "修改")
    @PostMapping("/update")
    public Boolean update(@RequestHeader("appCode") String appCode,
                                        @RequestBody DemoDTO demoDTO) {
    
    
      
        boolean addFlag = demoService.update(demoDTO);
        if (addFlag) {
    
    
            // 刷新资源
          demoService.refreshMap(appCode);
        }
        return addFlag;
    }


    @Override
    @ApiOperation(value = "删除", notes = "删除")
    @DeleteMapping("/delById")
    public Boolean deleteById(@RequestHeader("appCode") String appCode, @RequestParam Long id) {
    
    
        boolean deleteFlag = demoService.deleteById(id);
        if (deleteFlag) {
    
    
            // 刷新资源
          demoService.refreshMap(appCode);
        }
        return addFlag;
    }


    @Override
    @ApiOperation(value = "列表", notes = "列表")
    @GetMapping("/list")
    public List<DemoVO> list() {
    
    
        return demoService.list();
    }
 }

code d'essai

  1. Tests de composants individuels, pas besoin d'utiliser @SpringBootTest pour le démarrage du contexte global, utilisez @RunWith(SpringRunner.class) pour exécuter des cas de test.
  2. Injectez la classe de contrôleur en utilisant @InjectMock.
  3. Annotez la classe de service fictive avec @Mock.
@RunWith(SpringRunner.class)
public class DemoControllerTest {
    
    
    /**
     * mock mvc
     */
    private MockMvc mockMvc;


    /**
     * 注入实例
     */
    @InjectMocks
    private DemoController demoController;


    /**
     * service mock
     */
    @Mock
    private DemoService demoService;
    
    /**
     * appCode
     */
    private String appCode;


    /**
     * before设置
     */
    @Before
    public void setUp() {
    
    
        //初始化带注解的对象
        MockitoAnnotations.openMocks(this);
        //构造mockmvc
        mockMvc = MockMvcBuilders.standaloneSetup(demoController).build();
        //appCode
        appCode = "AppCode_test";
    }


    /**
     * 测试testAdd
     */
    @Test
    public void testAdd() throws Exception {
    
    
        //构建dto
        DemoDTO demoDTO = new DemoDTO();
        //setId
        demoDTO.setId(-1L);
        //setName
        demoDTO.setName("test");
        //mock service方法
   		PowerMockito.when(demoService.add(demoDTO)).thenReturn(true);
        //构造body
        String body = JSONObject.toJSONString(demoDTO);
        //执行mockmvc
        this.mockMvc.perform(MockMvcRequestBuilders.post("/demo/create")
                //传参
                .header("appCode", appCode).content(body).contentType(MediaType.APPLICATION_JSON_VALUE))
                //mock返回
                .andExpect(status().isOk()).andDo(MockMvcResultHandlers.print()).andReturn();
    }


    /**
     * 测试testUpdate
     */
    @Test
    public void testUpdate() throws Exception {
    
    
          //构建dto
        DemoDTO demoDTO = new DemoDTO();
        //setId
        demoDTO.setId(-1L);
        //setName
        demoDTO.setName("test");
        //mock service方法
        PowerMockito.when(demoService.update(demoDTO)).thenReturn(true);
        //构造body
        String body = JSONObject.toJSONString(demoDTO);
        //执行mockmvc
        this.mockMvc.perform(MockMvcRequestBuilders.post("/demo/update")
                //传参
                .header("appCode", appCode).content(body).contentType(MediaType.APPLICATION_JSON_VALUE))
                //mock返回
                .andExpect(status().isOk()).andDo(MockMvcResultHandlers.print()).andReturn();
    }


    /**
     * 测试testDelete
     */
    @Test
    public void testDelete() throws Exception {
    
    
        //Id
        Long id = 1000L;
        //mock service方法
        PowerMockito.when(demoService.deleteById(id)).thenReturn(true);
        //执行mockmvc 方法一
//        this.mockMvc.perform(MockMvcRequestBuilders.delete("/demo/delById?id={id}",id)
//                //传参
//                .header("appCode", appCode).contentType(MediaType.APPLICATION_JSON_VALUE))
//                //mock返回
//.andExpect(status().isOk()).andDo(MockMvcResultHandlers.print()).andReturn();
//    }
		//方法二
        this.mockMvc.perform(MockMvcRequestBuilders.delete("/demo/delById")
                //传参
                .header("appCode", appCode).param("id", "1000").contentType(MediaType.APPLICATION_JSON_VALUE))
                //mock返回
                .andExpect(status().isOk()).andDo(MockMvcResultHandlers.print()).andReturn();
    }


    /**
     * 测试testList
     */
    @Test
    public void testList() throws Exception {
    
    
        this.mockMvc.perform(MockMvcRequestBuilders.get("/demo/list")
                //传参
                .contentType(MediaType.APPLICATION_JSON_VALUE))
                //mock返回
                .andExpect(status().isOk()).andDo(MockMvcResultHandlers.print()).andReturn();
    }
}

Test unique de la couche de service

code sous test

@Service 
public class MenuService {
    
     
    @Autowired 
    private MenuMapper menuMapper; 
    
    @Transactional(readOnly = true) 
    public List<Menu> listMenus() {
    
     
        final List<Menu> result = menuMapper.list(); 
        return result; 
    }
} 

code d'essai

  1. En @TestConfiguration créant une configuration de test, une déclaration est fournie dans le fichier configuration MenuService Bean.
  2. L'utilisation de cette annotation présente les points suivants : la classe annotée doit être statique et ne peut pas être privée. Il est recommandé de l'utiliser dans les classes internes, sinon le bean défini ne sera pas automatiquement chargé. Doit être chargé de l'une des manières suivantes
@Import(MenuServiceTestConfig.class)
@ContextConfiguration(classes =MenuServiceTestConfig.class)
@Autowired
//此处通过 @Autowired 自动注入的是上面通过 @TestConfiguration 声明的 Bean。
@RunWith(SpringRunner.class) 
public class MenuServiceTest {
    
     
    @TestConfiguration 
    static class MenuServiceTestConfig {
    
     
        @Bean 
        public MenuService mockMenuService() {
    
     
            return new MenuService(); 
        } 
    }
    @Autowired 
    private MenuService MenuService; 
    @MockBean 
    private MenuMapper MenuMapper; 
    @Test 
    public void listMenus() {
    
     
        List<Menu> menus = new ArrayList<Menu>() {
    
    {
    
     
            this.add(new Menu()); 
        }}; 
        Mockito.when(menuMapper.list()).thenReturn(menus); 
        List<Menu> result = menuService.listMenus(); 
        Assertions.assertThat(result.size()).isEqualTo(menus.size()); 
    } 
}

protocole de test unique

  1. [Obligatoire] Un bon test unitaire doit suivre les principes AIR.
    Explication : lorsque le test unitaire s'exécute en ligne, on a l'impression que l'air (AIR) n'existe pas, mais il est très important d'assurer la qualité du test. Macroscopiquement parlant, un bon test unitaire a les caractéristiques d'automatisation, d'indépendance et de répétabilité.
AAutomatic(自动化)
IIndependent(独立性)
RRepeatable(可重复)
  1. [Obligatoire] Les tests unitaires doivent être exécutés de manière entièrement automatique et non interactive.
    Explication : Les scénarios de test sont généralement exécutés de manière régulière et le processus d'exécution doit être entièrement automatisé pour avoir un sens. Un test dont la sortie nécessite une inspection humaine n'est pas un bon test unitaire. System.out n'est pas autorisé à être utilisé pour la vérification humaine dans les tests unitaires, et assert doit être utilisé pour la vérification.
  2. [Obligatoire] Gardez les tests unitaires indépendants.
    Remarque : Afin de s'assurer que le test unitaire est stable, fiable et facile à maintenir, les cas de test unitaire ne doivent pas s'appeler, ni dépendre de l'ordre d'exécution.
    Contre-exemple : method2 doit s'appuyer sur l'exécution de method1 et utilise le résultat de l'exécution comme entrée de method2.
  3. [Obligatoire] Les tests unitaires peuvent être exécutés à plusieurs reprises et ne peuvent pas être affectés par l'environnement externe.
    Description : les tests unitaires sont généralement placés en intégration continue et les tests unitaires seront exécutés à chaque enregistrement de code. Si le test unitaire dépend de l'environnement externe (réseau, service, middleware, etc.), il conduira facilement à l'indisponibilité du mécanisme d'intégration continue.
    Exemple positif : Afin de ne pas être affecté par l'environnement externe, il est nécessaire de changer la dépendance du SUT à l'injection lors de la conception du code, et d'utiliser un framework DI tel que spring pour injecter une implémentation locale (mémoire) ou une implémentation Mock lors des tests.
  4. [Obligatoire] Pour les tests unitaires, assurez-vous que la granularité du test est suffisamment petite pour aider à identifier les problèmes. La granularité de mesure unique est au niveau de la classe, généralement au niveau de la méthode.
    Remarque : Ce n'est que lorsque la granularité du test est faible que l'emplacement de l'erreur peut être localisé dès que possible lorsqu'une erreur se produit. Les tests unitaires ne sont pas chargés de vérifier la logique d'interaction inter-classes ou inter-systèmes, qui est le domaine des tests d'intégration.
  5. [Obligatoire] Les codes incrémentiels pour l'activité principale, les applications principales et les modules principaux garantissent la réussite des tests unitaires.
    Remarque : Ajoutez un nouveau code pour compléter le test unitaire à temps. Si le nouveau code affecte le test unitaire d'origine, veuillez le corriger à temps.
  6. [Obligatoire] Le code de test unitaire doit être écrit dans le répertoire de projet suivant : src/test/java, et il n'est pas autorisé à être écrit dans le répertoire de code métier.
    Remarque : Ce répertoire sera ignoré lors de la construction du code source, et le framework de test unitaire analyse ce répertoire par défaut.

Cadre PowerMock

simulation d'introduction

concept fictif

Mock fait référence à la création d'un objet virtuel pour simuler le comportement d'un objet spécifié lors des tests.

effet simulacre

  1. Le service-A dépend du service-B. Lors du test du service-A, le service-B n'a pas encore été développé. Certains comportements du service-B sont simulés par simulation pour obtenir l'effet de test.
  2. Les objets avec des constructeurs privés ne peuvent pas être construits directement, mais peuvent être construits via des simulations.
  3. Le module testé doit se connecter à la base de données et à d'autres opérations, et il ne peut être garanti de pouvoir se connecter à la base de données pendant le test, ce qui peut être réalisé par moquerie.
  4. … …

Présentation de PowerMock

  1. PowerMock est un framework de simulation Java à test unique qui étend les frameworks EasyMock et Mockito.
  2. PowerMock effectue des simulations en fournissant des classes personnalisées ainsi que des astuces de manipulation de bytecode.
  3. PowerMock peut simuler des méthodes statiques, des méthodes privées, des constructeurs, des méthodes finales, etc.
  4. PowerMock prend en charge JUnit et TestNG.

Dépendances PowerMock pom

<properties>
    <powermock.version>2.0.9</powermock.version>
</properties>
<dependencies>
   <dependency>
      <groupId>org.powermock</groupId>
      <artifactId>powermock-module-junit4</artifactId>
      <version>${
    
    powermock.version}</version>
      <scope>test</scope>
   </dependency>
   <dependency>
      <groupId>org.powermock</groupId>
      <artifactId>powermock-api-mockito2</artifactId>
      <version>${
    
    powermock.version}</version>
      <scope>test</scope>
   </dependency>
</dependencies>

Avis:

Cette dépendance convient à JUnit4.4 et supérieur.

Fonction PowerMock

  • constructeurs fictifs
  • méthode ou classes finales fictives
  • fausses méthodes privées
  • méthodes statiques fictives
  • Si vous êtes intéressé
    , vous pouvez effectuer une recherche sur le site officiel.La version se concentre sur certaines fonctions fictives couramment utilisées.

Exemples fictifs courants de PowerMock

modèle fictif

@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringRunner.class)
@PrepareForTest({
    
    XxxUtils.class})
public class DemoServiceImplTest {
    
    
    /**
     * 注入service
     */
    @InjectMocks
    private DemoServiceImpl demoService;

    /**
     * mapper
     */
    @MockBean
private DemoMapper demoMapper;

@Before
public void setUp() {
    
    
      //构建mybatis缓存
      TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new MybatisConfiguration(), ""), DemoEntity.class);
}

@Test
public void testCreateDemo() {
    
    
   //todo
}
}

simulacre de constructeur privé

Prenons l'exemple de la classe Result encapsulée par le département, certaines des méthodes de construction privées ne peuvent pas construire de paramètres et une simulation de construction est requise.

Result<List<UserInfoDTO>> result = Whitebox.invokeConstructor(Result.class, "200", "", true, userInfoDTOList);

Méthodes privées fictives et propriétés privées

//mock 当前service类
ServiceA serviceMock= PowerMockito.mock(ServiceA.class);
//内部调用其他service需设置非公共成员
Whitebox.setInternalState(serviceMock, "serviceB", serviceB);
//mock调用其他service方法
PowerMockito.when(serviceB.getStr("xxx")).thenReturn("xxxxx");
//调用内部私有方法
Whitebox.invokeMethod(serviceMock, "privateMethod1", demoDto);

illustrer:

  1. La classe ServiceB est injectée dans la classe ServiceA et la méthode getStr(String str) est appelée.
  2. La méthode privée privateMethod1 de la classe ServiceA est passée en paramètre à DemoDto.

méthode statique fictive

  1. Ajouter des annotations de méthode statique qui doivent être testées
@PrepareForTest({
    
    StaticXXX.class})
  1. Tester un faux appel
//mock静态类
PowerMockito.mockStatic(StaticXXX.class);
//mock调用静态方法
PowerMockito.when(StaticXXX.method01("param01", "param02")).thenReturn(xxx);

configuration fictive

@MockBean
private DemoProperties demoProperties ;
  1. Utilisez @MockBean pour introduire les classes de configuration
  2. valeur de prise d'appel
//构造demoProperties 
DemoProperties .DemoFirstProperties demoFirstProperties = new DemoProperties .DemoFirstProperties ();
//塞值
demoFirstProperties .setFirstParams("xxxx");
//mock properties
PowerMockito.when(demoProperties .getDemoFirstProperties ()).thenReturn(demoFirstProperties );

Le retour de la valeur de la méthode publique de la classe d'objets fictifs

  1. classe d'objet
public class SmsResponse implements Serializable {
    
    
    /**
     * 编码 1-成功
     */
    private Integer code;
    /**
     * 返回内容
     */
    private String msg;
    public boolean isSuccess(){
    
    
        return null != code && 200 == code;
    }
    public Integer getCode() {
    
    
        return code;
    }
    public void setCode(Integer code) {
    
    
        this.code = code;
    }
    public String getMsg() {
    
    
        return msg;
    }
    public void setMsg(String msg) {
    
    
        this.msg = msg;
    }
}
  1. La valeur de retour de l'appel de méthode isSuccess() dans cette classe est utilisée dans le code
// 发送短信
SmsResponse smsResponse = this.smsNoticeService.sendSms(sms);
if (smsResponse.isSuccess()) {
    
    
    if (Objects.nonNull(noticeTimes) && Objects.nonNull(smsNotice)) {
    
    
        // 短信发送成功,更新通知标识
        noticeTimes.put(NoticeChannelEnum.SMS.getDesc(),smsNotice);
    }
    result.put(MSG,"");
    return result;
}

À ce stade, si vous souhaitez entrer dans la branche if, vous devez vous moquer de l'opération

SmsResponse smsResponse = PowerMockito.mock(SmsResponse.class);
PowerMockito.when(smsResponse.isSuccess()).thenReturn(true);
when(this.smsNoticeService.sendSms(any(Sms.class))).thenReturn(smsResponse);

déminage

@SpringBootTest

question:

  1. @SpringBootTest analysera la configuration Spring de l'application et créera un contexte Spring complet. Chaque fois qu'un test unitaire d'une classe est exécuté, tout le contexte doit être démarré et la vitesse du test unique est lente !
  2. Lorsque @SpringBootTest charge le contexte Spring, cela peut entraîner le démarrage de la classe de test en raison de l'échec du chargement de la base de données, de MQ, du cache et d'autres configurations utilisées dans le service.
  3. @SpringBootTest est plus adapté aux tests d'intégration fonctionnelle.

solution:

Utilisez @RunWith(SpringRunner.class) pour déclarer que le test est effectué dans l'environnement Spring, afin que les annotations liées à Spring soient reconnues et efficaces.

Utilisation combinée de SpringBoot+PowerMock+Mockito

question:

Lorsqu'il est utilisé en combinaison avec powermock, il est facile de provoquer des conflits entre certaines classes et méthodes, ce qui fait que la méthode n'est pas trouvée.

solution:

La version de dépendance correspond à :

Mockito PowerMock
2.8.9+ 2.x
2.8.0-2.8.9 1.7.x
2.7.5 1.7.0RC4
2.4.0 1.7.0RC2
2.0.0-bêta - 2.0.42-bêta 1.6.5-1.7.0RC
1.10.8 - 1.10.x 1.6.2 - 2.0
1.9.5-rc1 - 1.9.5 1.5.0 - 1.5.6
1.9.0-rc1 et 1.9.0 1.4.10 - 1.4.12
1.8.5 1.3.9 - 1.4.9
1.8.4 1.3.7 & 1.3.8
1.8.3 1.3.6
1.8.1 & 1.8.2 1.3.5
1.8 1.3
1.7 1.2.5

classe d'injection de constructeur

question:

Certaines autres classes injectées dans certaines classes de service sont injectées via des constructeurs au lieu des annotations @Autowired ou @Resource. comme

@Service 
public class MenuService {
    
     
   
    private MenuMapper menuMapper; 
@Autowired 
public MenuService(final MenuMapper menuMapper) {
    
    
    this.menuMapper = menuMapper;
}

    @Transactional(readOnly = true) 
    public List<Menu> listMenus() {
    
     
        final List<Menu> result = menuMapper.list(); 
        return result; 
    }
} 

solution:

Construire un service

@RunWith(SpringRunner.class) 
public class MenuServiceTest {
    
     

private static final MenuMapper menuMapper = Mockito.mock(MenuMapper.class);

    @TestConfiguration 
    static class MenuServiceTestConfig {
    
     
        @Bean 
        public MenuService mockMenuService() {
    
     
            return new MenuService(menuMapper); 
        } 
    }
    @Autowired 
    private MenuService MenuService; 
    @MockBean 
    private MenuMapper MenuMapper; 
    @Test 
    public void listMenus() {
    
     
        List<Menu> menus = new ArrayList<Menu>() {
    
    {
    
     
            this.add(new Menu()); 
        }}; 
        Mockito.when(menuMapper.list()).thenReturn(menus); 
        List<Menu> result = menuService.listMenus(); 
        Assertions.assertThat(result.size()).isEqualTo(menus.size()); 
    } 
}

La simulation de méthode statique signale une erreur org.powermock.api.mockito.ClassNotPreparedExceptionnot

question:

Lors de la simulation d'une méthode statique, une erreur est signalée indiquant que la classe statique est préparée pour le test

solution:

  1. Confirmez si l'annotation @PrepareForTest({Xxx.class}) est ajoutée à la classe pour préparer la classe statique.
  2. Vérifiez si l'environnement d'exécution @RunWith(PowerMockRunner.class) est utilisé lors de l'utilisation de PowerMock.

Mybatis signale MybatisPlusException

question:

Lorsque l'expression lambda a une méthode définie, le test unique signale une erreurcom.baomidou.mybatisplus.core.exceptions.MybatisPlusException: can not find lambda cache for this entity

solution:

Ajoutez du code à la méthode @Before dans la classe de test unitaire pour déclencher manuellement la collecte des informations de cache.

@Before
public void setUp() {
    
    
    //构建mybatis缓存
    TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new MybatisConfiguration(), ""), XxxEntity.class);
}

Parmi eux, XxxEntity.class est la classe d'entité de table.

référence

  1. protocole de test unique
  2. site officiel de la Junit
  3. printemps-boot-test
  4. base de code mybatis-plus

Je suppose que tu aimes

Origine blog.csdn.net/Andya_net/article/details/129264354
conseillé
Classement