在我的测试设置中,该行:
when(kc.getToken()).thenReturn(token);
不起作用,我从
ServiceImplementation
收到以下错误:
java.lang.NullPointerException: Cannot invoke "services.KeycloakService.getToken()" because "this.kc" is null
我正在使用以下依赖项:
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.mockito:mockito-core:5.14.2'
testImplementation 'org.mockito:mockito-junit-jupiter:5.14.2'
我尝试过的:
String zaToken = kc.getToken
并给出上述错误
@ExtendWith(MockitoExtension.class)
、@BeforeEach
和 @InjectMocks
,它们在我的其他测试中有效。但是,我也尝试了 MockitoAnnotations.initMocks(this) ,错误仍然存在。
服务实施代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
...
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
...
import services.AasService;
import services.KeycloakService;
@Service
public class AasServiceImpl implements AasService{
private final RestTemplate restTemplate;
@Autowired
private KeycloakService kc;
@Value("${ass.server}")
private String aasUri;
@Value("${ass.id}")
private String aasIdShort;
public AasServiceImpl (RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
@Override
public void update(String applicationUri, String nodeId, JSONObject value) {
System.out.println(applicationUri);
System.out.println(nodeId);
System.out.println(value);
String submodelElementValueId = applicationUri.replace(":", "_") + nodeId.replace("i=", "");
System.out.println(submodelElementValueId);
if (kc instanceof KeycloakServiceImpl) {
System.out.println("This is original service.");
} else {
System.out.println("This is not the original service.");
//this is the option printed
}
//problematic line is the following
String zaToken = kc.getToken();
//this is not printed in the code
System.out.println(zaToken);
try {
updateValue("DefectDetectionSkill", "Inputs", submodelElementValueId, value, zaToken);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
测试代码:
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.when;
...
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;
...
import org.junit.jupiter.api.BeforeEach;
import services.KeycloakService; //this is an interface
@ExtendWith(MockitoExtension.class)
public class AasServiceImplTest {
@Mock
private KeycloakService kc;
@Mock
private RestTemplate restTemplate;
@InjectMocks
private AasServiceImpl aasService;
@BeforeEach
void setUp() {
String token = "mockToken";
when(kc.getToken()).thenReturn(token);
ResponseEntity<String> response= new ResponseEntity<>("", HttpStatus.OK);
when(restTemplate.exchange(anyString(), any(), any(), eq(String.class))).thenReturn(response);
System.out.println("set up runs");
//this message is printed
}
/*
@Test
void testMockInjection() {
assertNotNull(kc, "KeycloakService mock is not injected!");
assertNotNull(restTemplate, "RestTemplate mock is not injected!");
assertNotNull(aasService, "AasServiceImpl is not initialized!");
}
*/
@Test
void testUpdate() {
//Arrange
String applicationUri = "http://mock_uri";
String nodeId="i=ioanna";
JSONObject value = new JSONObject();
value.put("Value", 1234);
//Act
aasService.update(applicationUri, nodeId , value);
System.out.println("Value: " + value.get("Value"));
//Assert
assertNotNull(kc, "KeycloakService mock is not injected!");
//verify(kc, times(1)).getToken();
//verify(restTemplate, atLeastOnce()).exchange(anyString(), any(), any(), eq(String.class));
}
看起来
@InjectMock
未能混合字段注入和构造函数参数注入。要么自动连接 restTemplate
和 kc
字段:
@Service
public class AasServiceImpl implements AasService {
// No explicit constructor!
@Autowired
private RestTemplate restTemplate;
@Autowired
private KeycloakService kc;
...
或者将它们都作为构造函数参数:
@Service
public class AasServiceImpl implements AasService {
private RestTemplate restTemplate;
private KeycloakService kc;
public AasServiceImpl (RestTemplate restTemplate, KeycloakService kc) {
this.restTemplate = restTemplate;
this.kc = kc;
}
...