J'essaie de faire un test d'intégration simple en utilisant Spring Boot Test afin de tester le cas d'utilisation e2e. Mon test ne fonctionne pas car je ne suis pas en mesure de faire enregistrer les données du référentiel, je pense que j'ai un problème avec les contextes de printemps ...
Ceci est mon entité:
@Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Person {
@Id
private int id;
private String name;
}
Voici le référentiel des personnes:
@Repository
public interface PersonRepository extends JpaRepository<Person, Integer> {
}
Le service Personne:
@Service
public class PersonService {
@Autowired
private PersonRepository repository;
public Person createPerson(int id,String name) {
return repository.save(new Person(id, name));
}
public List<Person> getPersons() {
return repository.findAll();
}
}
Le contrôleur de personne:
@RequestMapping
@RestController
public class PersonController {
@Autowired
private PersonService personService;
@RequestMapping("/persons")
public List<Person> getPersons() {
return personService.getPersons();
}
}
La classe d'application principale:
@SpringBootApplication
public class BootIntegrationTestApplication {
public static void main(String[] args) {
SpringApplication.run(BootIntegrationTestApplication.class, args);
}
}
Le fichier application.properties:
spring.datasource.url= jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=password
spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true
Et le test:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class BootIntegrationTestApplicationTests {
@Autowired
private PersonService personService;
@Autowired
private TestRestTemplate restTemplate;
@Test
@Transactional
public void contextLoads() {
Person person = personService.createPerson(1, "person1");
Assert.assertNotNull(person);
ResponseEntity<Person[]> persons = restTemplate.getForEntity("/persons", Person[].class);
}
}
Le test ne fonctionne pas, car le service ne sauvegarde pas l'entité Personne .... Merci d'avance
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
public class SmokeTest {
@Autowired
UserController userController;
@Autowired
UserDao userDAO;
@Rollback(false) // This is key to avoid rollback.
@Test
public void contextLoads() throws Exception {
System.out.println("Hiren");
System.out.println("started");
userDAO.save(new User("tyx", "[email protected]"));
}
}
Reportez-vous à @Rollback(false)
est la clé pour éviter un retour en arrière.
Merci à M. Deinum, je pense avoir compris, donc le mieux est de séparer la logique du test en deux tests, le premier testera juste le service (donc celui-ci pourrait être transactionnel) et le second le contrôleur:
Test 1:
@Test
@Transactional
public void testServiceSaveAndRead() {
personService.createPerson(1, "person1");
Assert.assertTrue(personService.getPersons().size() == 1);
}
Test 2:
@MockBean
private PersonService personService;
@Before
public void setUp() {
//mock the service
given(personService.getPersons())
.willReturn(Collections.singletonList(new Person(1, "p1")));
}
@Test
public void testController() {
ResponseEntity<Person[]> persons = restTemplate.getForEntity("/persons", Person[].class);
Assert.assertTrue(persons.getBody()!=null && persons.getBody().length == 1);
}
J'espère que cela aidera quelqu'un un jour ... merci pour vous tous
Pour chaque fonction @Test
Qui effectue une transaction de base de données, si vous souhaitez conserver de façon permanente les modifications, vous pouvez utiliser @Rollback(false)
@Rollback(false)
@Test
public void createPerson() throws Exception {
int databaseSizeBeforeCreate = personRepository.findAll().size();
// Create the Person
restPersonMockMvc.perform(post("/api/people")
.contentType(TestUtil.APPLICATION_JSON_UTF8)
.content(TestUtil.convertObjectToJsonBytes(person)))
.andExpect(status().isCreated());
// Validate the Person in the database
List<Person> personList = personRepository.findAll();
assertThat(personList).hasSize(databaseSizeBeforeCreate + 1);
Person testPerson = personList.get(personList.size() - 1);
assertThat(testPerson.getFirstName()).isEqualTo(DEFAULT_FIRST_NAME);
assertThat(testPerson.getLastName()).isEqualTo(DEFAULT_LAST_NAME);
assertThat(testPerson.getAge()).isEqualTo(DEFAULT_AGE);
assertThat(testPerson.getCity()).isEqualTo(DEFAULT_CITY);
}
Je l'ai testé avec un projet SpringBoot généré par jHipster:
N'utilisez pas @Rollback(false)
. Le test unitaire ne doit pas générer de données.
JPA FlushMode est AUTO
(par défaut - flush INSERT/UPDATE/DELETE SQL lorsque la requête se produit)/COMMIT
.
Il suffit de demander à l'entité de travail de forcer FLUSH ou d'utiliser EntityManager pour forcer le vidage
@Test
public void testCreate(){
InvoiceRange range = service.createInvoiceRange(1, InvoiceRangeCreate.builder()
.form("01GTKT0/010")
.serial("NV/18E")
.effectiveDate(LocalDate.now())
.rangeFrom(1L)
.rangeTo(1000L)
.build(), new byte[] {1,2,3,4,5});
service.findByCriteria(1, "01GTKT0/010", "NV/18E"); // force flush
// em.flush(); // another way is using entityManager for force flush
}
Le printemps pour enregistrer l'entité nécessite une transaction. Mais tant que la transaction n'a pas été validée, les modifications ne sont pas visibles depuis une autre transaction.
Le moyen le plus simple est d'appeler le contrôleur après une transaction de validation
@Test
@Transactional
public void contextLoads() {
Person person = personService.createPerson(1, "person1");
Assert.assertNotNull(person);
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
ResponseEntity<Person[]> persons = restTemplate.getForEntity("/persons", Person[].class);
}
});
}