【问题标题】:@TestPropertySource is not helping to fetch configuration property values@TestPropertySource 无助于获取配置属性值
【发布时间】:2020-01-29 18:56:06
【问题描述】:

在以下测试代码 sn-p 中,未从配置文件中获取 number_of_days.last 和 number_of_months.plan 的值。请检查并查看可能是什么原因。当我从服务类中删除 @Value 注释时ShiftPlanService.java 并用所需的值初始化那里的值,测试通过。

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

application.properties 文件如下-

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  

在 ShiftPlanService 类中,我有

@Value("${number_of_days.last}")
public int ndl;

@Value("${number_of_months.plan}")
public int nm;

【问题讨论】:

    标签: spring-boot mockito junit5


    【解决方案1】:

    我认为您打算使用 ShiftPlanService 的真实实例并注入模拟。您需要让 Spring 将 ShiftPlanService 自动装配到您的测试中,并告诉它像这样注入模拟:

    @Autowired
    @InjectMocks
    ShiftPlanService sps;
    

    尽管您可能会考虑在您的设置方法中自己实例化 ShiftPlanService,然后只传递您的模拟并在 ShiftPlanService 上设置其他属性。

    【讨论】:

    • 嗨,@SpyBean ShiftPlanService sps;没用。执行此操作后,我在 sps.createShiftPlan(4, 1, 2020); 行收到空指针异常
    • 我重读了你的问题,我认为这个问题与 Spring 没有在你的模拟中自动装配有关。您不需要为此使用间谍,因为您没有对 ShiftPlanService 进行任何间谍活动。
    【解决方案2】:

    您将 Mockito 注入与 Spring 注入混淆了。 @Value 是一个 Spring 概念,只有在 Spring 管理 bean 时才会被注入,但您在测试中拥有的 ShiftPlanService 实例是由 Mockito 使用 @Spy 注入的(正如已经指出的那样,你没有'真的需要)。

    我的建议是确定您想要什么 - 使用模拟的单元测试,或运行应用程序上下文的完整 Spring 测试。在我看来,您的意图是编写一个将所有内容都模拟出来的单元测试,在这种情况下:

    • 删除 @ContextConfiguration@TestPropertySource(单元测试不需要它们)
    • ShiftPlanService sps 上使用@InjectMocks 而不是@Spy - 它很可能会满足您的需求,具体取决于ShiftPlanService 的实现方式
    • sps中手动设置你需要的配置值;您可以添加设置器供测试使用;如果单元测试与类在同一个包中 - 这是一个很好的做法 - 它们也可以是包私有的 - 因为在生产中 Spring 会为你自动装配它们,所以你只需要它们进行测试
    • 哦,将 @Value 注释保留在您的 ShiftPlanService 中 - 生产需要它 - 如上所述

    【讨论】:

    • 嗨@Dariusz,我有以下疑问 - 1. 我应该在哪里添加这些设置器,在测试类中还是在 ShiftPlanService 类中? 2. 在同一个包中意味着如果 ShiftPlanService 在 src/main/java/ com.example.springboot.shift.planner.service 并且测试类在 src/test/java/com.example.springboot.shift.planner .service,它们在同一个包中吗?
    • (1) in ShitfPlanService,然后在测试中调用它们来设置测试中需要的值 (2) 是的,这是 (IMO) unit 的一个好习惯 测试(启动 Spring 的组件/集成测试是一个单独的测试类,通常存在于单独的包甚至模块中)。好处是您可以轻松知道在哪里可以找到生产类的相应测试,并且可以在测试需要时访问包私有(非公共)方法/构造函数,这些仍然对 API 客户端隐藏
    • ref (2) 再次,您的 source root (src/main/java vs src/test/java) 在 Java 中无关紧要,一旦编译,类仍然被认为在同一个包中。
    【解决方案3】:

    我们发明了一个 Mockito 扩展,允许轻松注入 String/Integer/Boolean 属性。查看自述文件,它非常易于使用,并且可以与 @InjectMocks 一起使用

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

    【讨论】:

    • 这与 Mockito 库已经提供的 @InjectMocks 有何不同?
    • @InjectMocks 不能注入字符串、整数、布尔值等。此扩展与 @InjectMocks 一起工作以实现这一点。
    猜你喜欢
    • 2019-03-22
    • 2016-02-24
    • 2016-01-27
    • 1970-01-01
    • 1970-01-01
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    • 2016-10-26
    相关资源
    最近更新 更多