Dans l'extrait de code de test suivant, les valeurs de number_of_days.last et number_of_months.plan ne sont pas extraites du fichier de configuration.Veuillez vérifier et voir quelle pourrait en être la raison.Lorsque je supprime l'annotation @Value de ma classe de service ShiftPlanService. java et initialisez simplement les valeurs avec les valeurs requises, le test réussit.
@Value("${number_of_days.last}") public int ndl; @Value("${number_of_months.plan}") public int nm;
Le fichier application.properties est le suivant-
server.port=8104 number_of_days.last= 7 number_of_months.plan= 2 spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/shiftplannerdatabase spring.datasource.username=root spring.datasource.password=WILLsuc95# #Keep the connection alive while idle for a long time spring.datasource.testWhileIdle= true spring.datasource.validationQuery= SELECT 1 # Show or not log for each sql query spring.jpa.show-sql = true # Hibernate ddl auto (create, create-drop, update) spring.jpa.hibernate.ddl-auto = update # Naming strategy spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy # Use spring.jpa.properties.* for Hibernate native properties (the prefix is # stripped before adding them to the entity manager) # The SQL dialect makes Hibernate generate better SQL for the chosen database spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
Dans la classe ShiftPlanService, j'ai
@ExtendWith(MockitoExtension.class) @ContextConfiguration(classes=SpringbootMysqlExampleApplication.class) @TestPropertySource(locations="src/main/resources/application.properties",properties= {"number_of_days.last= 7","number_of_months.plan= 2"}) class ShiftPlanServiceTest { @Mock ShiftPlanRepo mockedSpr; @Mock(lenient = true) ShiftDetailsRepo mockedSdr; @Mock(lenient = true) EmployeeDetailsRepo mockedEdr; @Spy ShiftPlanService sps; @BeforeEach public void setUp() { when(mockedSdr.findShiftNameById(1)).thenReturn("Morning"); when(mockedSdr.findShiftNameById(2)).thenReturn("Afternoon"); when(mockedEdr.getNameById(0)).thenReturn("Amit"); when(mockedEdr.getNameById(1)).thenReturn("Anupam"); when(mockedEdr.getNameById(2)).thenReturn("Chirag"); when(mockedEdr.getNameById(3)).thenReturn("Rashmi"); when(mockedEdr.count()).thenReturn(4L); } @Test public void testCreateShiftPlan() { sps.createShiftPlan(4, 1, 2020); verify(mockedSpr, times(36)).save(any(ShiftPlan.class)); verifyNoMoreInteractions(mockedSpr); } }
3 Réponses :
Je pense que vous avez l'intention d'utiliser une instance réelle de ShiftPlanService et d'avoir des simulations injectées. Vous devez avoir Spring autowire le ShiftPlanService dans votre test et lui dire d'injecter les simulacres comme ceci:
@Autowired @InjectMocks ShiftPlanService sps;
Bien que vous puissiez envisager d'instancier ShiftPlanService vous-même dans votre méthode de configuration et de simplement passer vos simulacres et définissez plutôt les autres propriétés sur ShiftPlanService.
Salut, @ SpyBean ShiftPlanService sps; n'a pas fonctionné. J'obtiens une exception de pointeur nul après cela, à la ligne sps.createShiftPlan (4, 1, 2020);
J'ai relu votre question et je pense que le problème est lié au fait que Spring ne se déclenche pas automatiquement dans vos simulacres. Vous ne devriez pas avoir besoin d'utiliser un espion pour cela puisque vous n'espionnez pas le ShiftPlanService.
Vous confondez l'injection de Mockito avec l'injection de printemps. @Value
est un concept Spring et ne sera injecté que lorsque Spring gère le bean, mais l'instance de ShiftPlanService
que vous avez dans votre test est injectée par Mockito code> en utilisant
@Spy
(dont vous n'avez pas vraiment besoin, comme cela a été souligné).
Ma recommandation serait de décider de ce que vous voulez: un test unitaire avec des simulacres ou un test Spring complet avec le contexte de l'application en cours d'exécution. Il me semble que votre intention est d'écrire un test unitaire avec tout simulé, auquel cas:
@ContextConfiguration
et @TestPropertySource
(vous n'en avez pas besoin pour les tests unitaires) @InjectMocks
au lieu de @Spy
sur ShiftPlanService sps
- il fera très probablement ce que vous voulez, selon la façon dont ShiftPlanService
est implémenté sps
; vous pouvez ajouter des setters pour ceux que le test doit utiliser; si le test unitaire est dans le même package que la classe - ce qui est une bonne pratique - ils peuvent également être privés de package - car en production, Spring les câblera automatiquement pour vous, vous n'en avez donc besoin que pour le test @Value
dans votre ShiftPlanService
- elle est nécessaire pour la production - comme expliqué ci-dessus Salut @Dariusz, j'ai les doutes suivants: 1. Où dois-je ajouter ces setters, dans la classe de test ou dans la classe ShiftPlanService? 2. être dans le même package signifie que ShiftPlanService est dans src / main / java / com.example.springboot.shift.planner.service et que la classe de test est dans src / test / java / com.example.springboot.shift.planner .service, sont-ils dans le même package?
(1) dans ShitfPlanService
, et vous les appelez dans le test pour définir les valeurs dont vous avez besoin dans le test (2) oui, c'est (IMO) une bonne pratique pour unité i > tests (les tests de composants / d'intégration où vous démarrez Spring sont une classe de tests distincte et vivent généralement dans un package séparé ou même un module). L'avantage est que vous savez facilement où trouver le test correspondant pour votre classe de production et que vous pouvez accéder aux méthodes / constructeurs privés (non publics) du package si nécessaire pour le test, qui sont toujours cachés des clients API.
ref (2) encore une fois, votre racine source (src / main / java vs src / test / java) n'a pas d'importance en Java une fois compilée, les classes sont toujours considérées comme étant dans le même package.
Nous avons inventé une extension Mockito qui permet d'injecter facilement des propriétés String / Integer / Boolean. Consultez le readme, il est très facile à utiliser et fonctionne avec @InjectMocks
En quoi est-ce différent du @InjectMocks
que la bibliothèque Mockito fournit déjà?
@InjectMocks
ne peut pas injecter des chaînes, des entiers, des booléens, etc. Cette extension fonctionne avec @InjectMocks
pour permettre cela.