L'équipe à laquelle j'appartiens a une règle selon laquelle s'il y a un problème, écrivez un code de test pour le reproduire (vérifiez la barre rouge) puis corrigez-le. L'autre jour, il y avait un problème de contrôle des transactions manquant, alors j'ai essayé d'écrire un code de test, mais comme j'étais confus, je vais l'organiser et le poster. Le code de test est répertorié sur Github (https://github.com/shimi58/transactiontest), veuillez donc vous y référer.
L'environnement construit sur Eclipse est le suivant. J'ai créé un projet Gradle et je l'ai passé par le chemin.
environnement | version |
---|---|
Java | 1.8 |
SpringBoot | 2.2.6 |
MyBatis | 2.1.0 |
H2 | PostgresqlMode |
Junit | 5(Jupiter) |
Enregistrez les informations sur les employés (nom, numéro de téléphone, adresse e-mail) et mettez à jour le numéro de la table des employés vers la table de statut. C'est une source d'échantillons telle que.
/**
* Service aux employés
*/
@Service
public class EmployeeService {
@Autowired
EmployeeRepository employeeRepository;
/**
* Inscription des employés
*/
@Transactional // ← C'était une fuite
public EmployeeNumber register(Employee employee) {
employeeRepository.registerEmployee(employee);
Employees employees = employeeRepository.findEmployees();
EmployeeNumber employeeNumber = employees.number();
employeeRepository.registerNumber(employeeNumber);
return employeeNumber;
}
}
Dans cet exemple de source, il est mis à jour en tant que table des employés → table des statuts, mais si la transaction n'est pas effective, si la mise à jour de la table des statuts échoue, elle est conservée dans la table des numéros et des statuts contenue dans la table des salariés. Le nombre de cas est incohérent.
À propos, la classe Controller sera mentionnée plus tard lorsque le code de test sera expliqué.
/**
* Contrôleur des employés
*/
@RestController
@RequestMapping("/employees")
public class EmployeesController {
@Autowired
EmployeeService employeeService;
/**
* Inscription des employés
*/
@RequestMapping(value = "/register", method = {RequestMethod.POST})
public String regist(@RequestBody Employee employee) {
EmployeeNumber employeeNumber = new EmployeeNumber(0);
try {
employeeNumber = employeeService.register(employee);
} catch (Exception e) {
System.out.println ("erreur de traitement");
}
return employeeNumber.toString();
}
}
Utilisez ** @SpyBean **.
SpyBean est une fonction de Spring Boot, et c'est un Suguremono qui ne fait qu'une partie du traitement de la classe que vous souhaitez tester dans Mock. Dans le cas de cet exemple de source, mock the EmployeeRepository avec SpyBean et
--registerEmployee: processus d'inscription des employés → Mise en œuvre normale --findEmployees: Traitement du nombre de tables des employés → Exécution normale --registerNumber: Processus de mise à jour de la table d'état → Une erreur s'est produite
Je veux créer une situation comme celle-là.
Le test est exécuté en appelant la classe Controller en tant que SpringBootTest. La classe Controller appelle la classe de service ci-dessus.
@SpringBootTest
public class EmployeesControllerTransactionTest {
MockMvc mockMvc;
@Autowired
private ObjectMapper mapper;
@Autowired
private EmployeesController employeesController;
// Cible fictive
@SpyBean
private EmployeeRepository employeeRepository;
/**
* Test de transaction
*
* Lorsqu'une erreur se produit lors de la mise à jour du nombre d'employés après l'enregistrement des informations sur les employés dans le tableau Employé, <br>
* Assurez-vous d'annuler l'enregistrement des informations sur les employés
*
* @throws Exception
*/
@ParameterizedTest
@CsvSource ({"Takao Hibi, 123-4345-2352, [email protected], 3"})
public void testTransaction(String name, String phone, String mail, int expected)
throws Exception {
Employee employee = new Employee(name, phone, mail);
// Convertir la requête au format Json
String json = mapper.writeValueAsString(employee);
// Paramètre d'occurrence d'erreur
doThrow(new RuntimeException()).when(employeeRepository)
.registerNumber(Mockito.any(EmployeeNumber.class));
this.mockMvc = MockMvcBuilders.standaloneSetup(employeesController).build();
// Émettre une demande
MvcResult result = mockMvc.perform(
post("/employees/register").contentType(MediaType.APPLICATION_JSON).content(json))
.andExpect(status().isOk()).andReturn();
String response = result.getResponse().getContentAsString();
Employees employees = employeeRepository.findEmployees();
System.out.println(response);
System.out.println(employees.toString());
EmployeeNumber actual = employees.number();
// Parce qu'il sera annulé, vérifiez qu'il est à l'état 3 avant l'enregistrement
assertEquals(expected, actual.getValue().intValue());
}
@SpringBootTest
public class EmployeesControllerTransactionTest {
Il est indispensable car il ne fera pas de DI à moins que SpringBootTest ne soit attaché.
@SpyBean
private EmployeeRepository employeeRepository;
Déclarez le référentiel à moquer.
@ParameterizedTest
@CsvSource ({"Takao Hibi, 123-4345-2352, [email protected], 3"})
Bien que cela n'ait rien à voir avec cet article, vous pouvez utiliser CsvSource pour effectuer des tests de variation avec une méthode. J'avais une longue histoire de Junit4, donc j'ai été impressionné quand j'ai réalisé que je pouvais le faire. Au fait, le nom a été emprunté à Amazing Name Generator. C'est devenu un monde pratique. (Plus hors de propos.)
// Paramètre d'occurrence d'erreur
doThrow(new RuntimeException()).when(employeeRepository)
.registerNumber(Mockito.any(EmployeeNumber.class));
Ici, il est déclaré qu'une RuntimeException sera générée lors du traitement de registerNumber.
this.mockMvc = MockMvcBuilders.standaloneSetup(employeesController).build();
Point Dohamari ①. Si vous ne faites pas standaloneSetup, mockMvc disparaîtra avec nullpo.
MvcResult result = mockMvc.perform(
post("/employees/register").contentType(MediaType.APPLICATION_JSON).content(json))
.andExpect(status().isOk()).andReturn();
Point Dohamari ②. Si ce n'est pas status (). IsOk (), il s'envolera (devac ne sera pas retourné). Je me suis inquiété pendant une heure lorsque l'URL de la publication était incorrecte et que 404 a été renvoyé, et pourquoi la réponse de débogage n'a pas eu lieu.
Lorsque j'ai exécuté le code de test, il s'est avéré être une merveilleuse barre verte!
Au fait, si vous supprimez @Transactional dans la classe de service,
Ouais, c'est une barre rouge. Si le nombre d'éléments dans la table des employés est différent d'un, une erreur d'assertion s'est produite et la transaction peut être confirmée.
Je regarderai seul en arrière.
Recommended Posts