S P*_*din 17 java junit spring mockito spring-boot
如何@Scheduled在spring-boot应用程序中测试作业任务?
package com.myco.tasks;
public class MyTask {
@Scheduled(fixedRate=1000)
public void work() {
// task execution logic
}
}
Run Code Online (Sandbox Code Playgroud)
Mac*_*iak 21
如果我们假设您的作业运行时间很短,您确实希望测试等待作业执行,并且您只想测试作业是否被调用,则可以使用以下解决方案:
将Awaitility添加到类路径:
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<version>3.1.0</version>
<scope>test</scope>
</dependency>
Run Code Online (Sandbox Code Playgroud)
写测试类似于:
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {
@SpyBean
private MyTask myTask;
@Test
public void jobRuns() {
await().atMost(Duration.FIVE_SECONDS)
.untilAsserted(() -> verify(myTask, times(1)).work());
}
}
Run Code Online (Sandbox Code Playgroud)
DwB*_*DwB 21
我的问题是:“你想测试什么?”
如果您的回答是“我想知道 Spring 在我想要的时候运行我的计划任务”,那么您正在测试 Spring,而不是您的代码。这不是您需要进行单元测试的内容。
如果您的回答是“我想知道我是否正确配置了我的任务”,那么编写一个带有频繁运行任务的测试应用程序,并验证该任务是否在您期望它运行时运行。这不是单元测试,但会表明您知道如何正确配置您的任务。
如果答案是“我想知道我编写的任务是否正确运行”,那么您需要对任务方法进行单元测试。在您的示例中,您希望对work()方法进行单元测试。通过编写一个直接调用您的任务方法 ( work())的单元测试来做到这一点。例如,
public class TestMyTask
{
@InjectMocks
private MyTask classToTest;
// Declare any mocks you need.
@Mock
private Blammy mockBlammy;
@Before
public void preTestSetup()
{
MockitoAnnotations.initMocks(this);
... any other setup you need.
}
@Test
public void work_success()
{
... setup for the test.
classToTest.work();
.. asserts to verify that the work method functioned correctly.
}
Run Code Online (Sandbox Code Playgroud)
@Maciej的回答解决了问题,但没有解决 @cristian-batista 提到的以太长的间隔(例如小时)测试 @Scheduled 的困难部分。
为了独立于实际的调度间隔来测试@Scheduled,我们需要使其可以通过测试进行参数化。幸运的是,Spring为此添加了一个fixedRateString参数。
这是一个完整的示例:
public class MyTask {
// Control rate with property `task.work.rate` and use 3600000 (1 hour) as a default:
@Scheduled(fixedRateString = "${task.work.rate:3600000}")
public void work() {
// task execution logic
}
}
Run Code Online (Sandbox Code Playgroud)
等待测试:
@RunWith(SpringRunner.class)
@SpringBootTest
// Override the scheduling rate to something really short:
@TestPropertySource(properties = "task.work.rate=100")
public class DemoApplicationTests {
@SpyBean
private MyTask myTask;
@Test
public void jobRuns() {
Awaitility.await().atMost(10, TimeUnit.SECONDS).untilAsserted(() ->
verify(myTask, Mockito.atLeastOnce()).work()
);
}
}
Run Code Online (Sandbox Code Playgroud)
这通常很难。您可以考虑在测试期间加载 Spring 上下文,并从中伪造一些 bean,以便能够验证计划的调用。
我的 Github 仓库中有这样的例子。有一个使用所描述的方法进行测试的简单预定示例。
| 归档时间: |
|
| 查看次数: |
22947 次 |
| 最近记录: |