網頁

2020/10/9

Spring Boot 測試使用@ActiveProfiles決定是否套用@EnableScheduling

Spring Boot測試時使用@ActiveProfiles決定測試類是否啟用@EnableScheduling的方式如下。

一般執行時可使用@ConditionalOnProperty來決定是否套用@EnableScheduling來啟用排程。而在Spring Boot測試時再利用@ActiveProfiles決定測試類執行時是否啟用@EnableScheduling


@ActiveProfilesvalue值代表測試時使用的properites,所以可以透過設定不同的properties來作為不同測試時使用的properties。

application.properties設定spring.profiles.active決定一般執行時使用的properties。例如設定執行時使用application-test.properties

application.properties

spring.profiles.active=test

application-test.propertiesscheduling.enabledfalse

application-test.properties

#Scheduling
scheduling.enabled=false

application-test.propertiesscheduling.enabledtrue

application-prod.properties

#Scheduling
scheduling.enabled=true

配置類SchedulingConfig@EnableScheduling前加上@ConditionalOnProperty設定如下。

SchedulingConfig

package com.abc.demo.config;

import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;

@ConditionalOnProperty(
        value = "scheduling.enabled", // 讀取application-xxx.properties的scheduling.enabled的值
        havingValue = "true", // scheduling.enabled為true則套用下面的annotation即@EnableScheduling的效果,反之@EnableScheduling會無效果
        matchIfMissing = false // default, 若scheduling.enabled沒設定則預設為false
)
@EnableScheduling // 依上面@ConditionalOnProperty的條件決定是否套用
@Configuration
public class SchedulingConfig {
}

DemoScheduleTaskDemoService為被測試的對象。
DemoScheduleTask為排程程式;
DemoService為一般(非排程)程式。

DemoScheduleTask

package com.abc.demo.schedule;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class DemoScheduleTask {

    @Scheduled(fixedRate = 3000)
    public void printUnixEpochTime() {
        System.out.println(System.currentTimeMillis());
    }

}

DemoService

package com.abc.demo.service;

import org.springframework.stereotype.Service;

@Service
public class DemoService {

    public int plus(int x, int y) {
        return x + y;
    }

}

DemoScheduleTaskTests為測試DemoScheduleTask排程的測試類,執行時要啟用@EnableScheduling@ActiveProfiles的值設為prod,代表測試執行時使用application-prod.properties的設定,也就是scheduling.enabled=true

DemoScheduleTaskTests

package com.abc.demo.schedule;

import org.awaitility.Awaitility;
import org.awaitility.Durations;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.test.context.ActiveProfiles;

@ActiveProfiles("prod")
@SpringBootTest
class DemoScheduleTaskTests {

    private final static int MIN_NUMBER_OF_INVOCATIONS = 2;

    @SpyBean // 用@SpyBean才可被Mockito.verify驗證備測試對象的調用次數
    private DemoScheduleTask demoScheduleTask;

    /**
     * 測試DemoScheduleTask.printUnixEpochTime()在10秒鐘至少被執行2次
     */
    @Test
    void printUnixEpochTime_testInvocationAtLeastTwoTimesDuringTenSeconds() {
        Awaitility.await()
                .atMost(Durations.TEN_SECONDS) // 等待期間10秒
                .untilAsserted( // 直到assert發生停止等待
                        () -> Mockito.verify(demoScheduleTask, Mockito.atLeast(MIN_NUMBER_OF_INVOCATIONS))
                                .printUnixEpochTime()); // 驗證demoScheduleTask.printUnixEpochTime()被調用2次
    }
}

DemoServiceTests為測試DemoService的測試類,執行時不啟用@EnableScheduling@ActiveProfiles的值設為test,代表測試執行時使用application-test.properties的設定,也就是scheduling.enabled=false

DemoServiceTests

package com.abc.demo.service;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;

@ActiveProfiles("test")
@SpringBootTest
class DemoServiceTests {

    @Autowired
    private DemoService demoService;

    @Test
    void plus_test() {

        int x = 1;
        int y = 2;

        int actual = demoService.plus(x, y);

        int expected = x + y;
        Assertions.assertEquals(expected, actual);

    }
}

則執行DemoScheduleTaskTests中的測試方法時會啟用排程;
執行DemoServiceTests中的測試方法時不會啟用排程。


參考github


沒有留言:

張貼留言