1
votes

@TestPropertySource n'aide pas à récupérer les valeurs des propriétés de configuration

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);
        }
   } 


0 commentaires

3 Réponses :


0
votes

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.


2 commentaires

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.



0
votes

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 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:

  • supprimez @ContextConfiguration et @TestPropertySource (vous n'en avez pas besoin pour les tests unitaires)
  • utilisez @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é
  • définissez manuellement les valeurs de configuration dont vous avez besoin dans 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
  • oh, et conservez l'annotation @Value dans votre ShiftPlanService - elle est nécessaire pour la production - comme expliqué ci-dessus

3 commentaires

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é 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.



0
votes

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

https://github.com/exabrial/mockito-object-injection


2 commentaires

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.