簡體   English   中英

通過集成測試執行生產代碼時的@Autowired 字段 null

[英]@Autowired field null when executing production code via integration tests

在過去的幾天里,我一直在摸不着頭腦,有點奇怪。 我有一個 JPA 存儲庫,它被現場注入到服務 class 中。在運行服務器並通過客戶端發送請求時工作完美,但是當通過集成測試執行代碼時,注入的字段 class (CustomerRepository) 始終是 null。

我已經通過 inte.net 嘗試了各種建議,但我沒有找到與我類似的情況,任何幫助將不勝感激

客服 class

@GRpcService
public class CustomerService extends CustomerServiceGrpc.CustomerServiceImplBase {

    @Autowired
    private CustomerRepository repository;

    @Override
    public void createCustomer(CreateCustomerRequest request, StreamObserver<CreateCustomerResponse> responseObserver) {

        final CustomerDao convertedDao = ProtoToDaoConverter.convertCustomerRequestProtoToCustomerDao(request);

        repository.save(convertedDao);

        responseObserver.onNext(CreateCustomerResponse.newBuilder().setSuccess(true).build());
        responseObserver.onCompleted();
    }
}

集成測試

@ExtendWith(SpringExtension.class)
@SpringBootTest
public class CustomerServiceIT {

    @Rule
    private final GrpcCleanupRule grpcCleanup = new GrpcCleanupRule();

    @Test
    public void something() throws IOException {

        String serverName = InProcessServerBuilder.generateName();

        // Create a server, add service, start, and register for automatic graceful shutdown.
        grpcCleanup.register(InProcessServerBuilder
                .forName(serverName).directExecutor().addService(new CustomerService()).build().start());

        customerServiceGrpc.CustomerServiceBlockingStub blockingStub = CustomerServiceGrpc.newBlockingStub(
                // Create a client channel and register for automatic graceful shutdown.
                grpcCleanup.register(InProcessChannelBuilder.forName(serverName).directExecutor().build()));

        final CreateCustomerRequest request = CreateCustomerRequest.newBuilder().setFirstName("Simon").setSecondName("Brown").setRole("Product Developer").build();

        final CreateCustomerResponse response = blockingStub.createCustomer(request);
    }

}

您可以使用Mockito或任何其他測試框架來模擬您的 class 依賴項(您的服務和您的 JPA 存儲庫)。

您可以使用這些功能:

  • @InjectMocks - 實例化測試 object 實例,並嘗試將用@Mock@Spy注釋的字段注入到測試 object 的私有字段中
  • @Mock - 創建它注釋的字段的模擬實例

在您的測試 class 中,您必須使用@Mock來注入“假存儲庫”:

@ExtendWith(SpringExtension.class)
@SpringBootTest
public class CustomerServiceTest {

    @InjectMocks
    private CustomerService testingObject;

    @Mock
    private CustomerRepository customRepository;

    @Rule
    private final GrpcCleanupRule grpcCleanup = new GrpcCleanupRule();

    @BeforeMethod
    public void initMocks(){
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void something() throws IOException {

    // inside the testing method you have to define what you mocked object should return.
    // it means mocking the CustomRepository methods

    CustomerDao customer = new CustomerDao(); // fill it with data
    Mockito.when(customRepository.save()).thenReturn(customer);


        // Create a server, add service, start, and register for automatic graceful shutdown.
        grpcCleanup.register(InProcessServerBuilder
                .forName(serverName).directExecutor().addService(new CustomerService()).build().start());

        customerServiceGrpc.CustomerServiceBlockingStub blockingStub = CustomerServiceGrpc.newBlockingStub(
                // Create a client channel and register for automatic graceful shutdown.
                grpcCleanup.register(InProcessChannelBuilder.forName(serverName).directExecutor().build()));

        final CreateCustomerRequest request = CreateCustomerRequest.newBuilder().setFirstName("Simon").setSecondName("Brown").setRole("Product Developer").build();

        final CreateCustomerResponse response = blockingStub.createCustomer(request);
    }

}

由於您的存儲庫及其方法是模擬的,因此您的 customerService 應該填充虛假數據以用於測試目的。

注意:很高興有一個類的命名約定,尤其是測試類。 一個常見的用法是總是像我在答案中所做的那樣給出 xxTest 的后綴

如果無法閱讀堆棧跟蹤,就很難回答。 我會通過查看 spring 上下文配置類來開始調查這個問題。 也許其中一些在集成測試的運行時丟失了。

如果您的應用程序中存在 spring @Configuration或其他@Component類,則可能有助於在您的測試中顯式加載它們,以及意外的空值CustomerRepository

@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = {AppConfig.class, CustomerRepository.class })
public class CustomerServiceIT {

這可能無法解決問題,但可能會揭示一些有助於您調查問題的錯誤消息。

在測試中,您調用new CustomerService() 您自己創建一個 object,而不是通過 spring。我想您應該在測試 class 中創建一個字段

@Autowired private final CustomerService customerService

並將其傳遞給grpcCleanup.register(InProcessServerBuilder.forName(serverName).directExecutor().addService(customerService).build().start());

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM