英文:
Testing RepositorSpring Boot Integration Test - mock returns null
问题
我在集成测试我的SpringBoot应用程序时遇到了问题。
这是我要测试的类的基本结构:
@Controller
@RequiredArgsConstructor
public class PushNotificationController {
private final PushNotificationService pnSvc;
private final PushNotificationRepository pnRepo;
private final DeviceTokenRepository dtRepo;
/**
* This method sends all PushNotifications from memory,
* which are not sent yet.
*/
public List<MiddlemanResponse> send() {
List<MiddlemanResponse> middlemanResponses = pnSvc.sendAll(dtRepo.findBySendStatus(DeviceTokenEntity.Status.SCHEDULED));
return middlemanResponses;
}
}
正如您所见,它依赖于两个存储库,这些存储库是继承自JpaRepository的接口,以及一个Service类。所有这些都是通过lombok的RequiredAllArgs构造函数进行注入的。
在我的测试中,我正在与H2数据库进行通信,这很好运行,我还想模拟pnSvc
。
这是我的测试类:
@RunWith(SpringRunner.class)
@SpringBootTest
public class PushNotificationControllerIntegrationTest {
@Autowired
private PushNotificationController underTest;
@Autowired
private DeviceTokenRepository dtRepo;
@Autowired
private PushNotificationRepository pnRepo;
@MockBean //我们模拟这个依赖,因为我们不想发送实际通知
private PushNotificationService pnSvc;
//testvalues
private final Long FIRST_PUSH_NOTIFICATION_ID = 1L;
private final Long FIRST_DEVICE_TOKEN_ID = 1L;
PushNotificationEntity pushNotification = new PushNotificationEntity(FIRST_PUSH_NOTIFICATION_ID, "message", "customString", 1L, "metadata");
DeviceTokenEntity deviceToken = new DeviceTokenEntity(FIRST_DEVICE_TOKEN_ID, "deviceToken", pushNotification, DeviceTokenEntity.Platform.IPHONE, "applicationType","brandId", DeviceTokenEntity.Status.SCHEDULED);
@Before
public void setUp() throws MiddlemanException {
when(pnSvc.sendAll(dtRepo.findBySendStatus(DeviceTokenEntity.Status.SCHEDULED))).thenReturn(List.of(new MiddlemanResponse(deviceToken, "response_message")));
pnRepo.save(pushNotification);
dtRepo.save(deviceToken);
}
@Test
public void sendOneSuccessTest() {
List<MiddlemanResponse> responses = underTest.send();
assertEquals(1, responses.size());
}
}
不幸的是,模拟的方法pnSvc.sendAll(...)
返回null
,因此MiddlemanResponse列表为空,我的测试失败并显示如下错误:
org.opentest4j.AssertionFailedError: expected: <1> but was: <0>
Expected :1
Actual :0
我的期望是,模拟的方法应该返回设置的值List.of(new MiddlemanResponse(deviceToken, "response_message"))
。
解决方案
感谢dbl和Gianluca Musa的回复,我采用了Gianluca Musa的方法,使用any()
来模拟响应,而不是传递实际参数
-> pnSvc.sendAll(any())
在模拟响应时
此外,我没有使用Gianluca Musa提出的org.mockito.Matchers.any
,而是使用了org.mockito.Mockito.any
,因为它已经被弃用。
英文:
I'm having trouble with integration testing my SpringBoot application.
This is the basic structure of my class under test:
@Controller
@RequiredArgsConstructor
public class PushNotificationController {
private final PushNotificationService pnSvc;
private final PushNotificationRepository pnRepo;
private final DeviceTokenRepository dtRepo;
/**
* This method sends all PushNotifications from memory,
* which are not sent yet.
*/
public List<MiddlemanResponse> send() {
List<MiddlemanResponse> middlemanResponses = pnSvc.sendAll(dtRepo.findBySendStatus(DeviceTokenEntity.Status.SCHEDULED));
return middlemanResponses;
}
}
As you can see it depends on two repositories which are interfaces extending from JpaRepository and a Service-class. All of them are injected via lombok RequiredAllArgs-constructor.
Inside my test I am communicating with an H2 database which works fine and also I want to mock the pnSvc
.
Here is my testclass:
@RunWith(SpringRunner.class)
@SpringBootTest
public class PushNotificationControllerIntegrationTest {
@Autowired
private PushNotificationController underTest;
@Autowired
private DeviceTokenRepository dtRepo;
@Autowired
private PushNotificationRepository pnRepo;
@MockBean //we mock this dependency because we dont want to send actual notifications
private PushNotificationService pnSvc;
//testvalues
private final Long FIRST_PUSH_NOTIFICATION_ID = 1L;
private final Long FIRST_DEVICE_TOKEN_ID = 1L;
PushNotificationEntity pushNotification = new PushNotificationEntity(FIRST_PUSH_NOTIFICATION_ID, "message", "customString", 1L, "metadata");
DeviceTokenEntity deviceToken = new DeviceTokenEntity(FIRST_DEVICE_TOKEN_ID, "deviceToken", pushNotification, DeviceTokenEntity.Platform.IPHONE, "applicationType","brandId", DeviceTokenEntity.Status.SCHEDULED);
@Before
public void setUp() throws MiddlemanException {
when(pnSvc.sendAll(dtRepo.findBySendStatus(DeviceTokenEntity.Status.SCHEDULED))).thenReturn(List.of(new MiddlemanResponse(deviceToken, "response_message")));
pnRepo.save(pushNotification);
dtRepo.save(deviceToken);
}
@Test
public void sendOneSuccessTest() {
List<MiddlemanResponse> responses = underTest.send();
assertEquals(1, responses.size());
}
}
Unfortunatly the mocked method pnSvc.sendAll(...)
returns null
, therefore the List of MiddlemanResponse is empty and my test fails with:
org.opentest4j.AssertionFailedError: expected: <1> but was: <0>
Expected :1
Actual :0
My expectation is that the mocked method should return the set value List.of(new MiddlemanResponse(deviceToken, "response_message")
.
SOLUTION
Thanks to dbl and Gianluca Musa for your replies I went with Gianluca Musa's approach of using any() instead of passing an actual parameter
-> pnSvc.sendAll(any())
when mocking the response
Also I did not use Gianluca Musa's proposed org.mockito.Matchers.any
but rather org.mockito.Mockito.any
because of its deprecaion.
答案1
得分: 2
可能的错误是模拟的过滤器不正确,您可以使用通用选择器来模拟 sendAll (),请尝试这样做:
when(pnSvc.sendAll(org.mockito.Mockito.any())).thenReturn(List.of(new MiddlemanResponse(deviceToken, "response_message")));
英文:
Probably the mistake is that the filter for the mock is incorrect, you can use a generic selector to simulate sendAll (), try this
when(pnSvc.sendAll(org.mockito.Mockito.any()).thenReturn(List.of(new MiddlemanResponse(deviceToken, "response_message")));
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论