JaegerTracer 的模拟在 Spring Boot 中给出空指针异常

问题描述 投票:0回答:1

任何人都可以帮我解决我在尝试为 Springboot 中具有 JaergerTracer 的服务编写 Junit 时遇到的空指针异常吗? 我有一个 Spring Boot 服务,该服务使用 Jaeger 进行跨度..该服务工作正常,但 Junit 给出了 NPE,因为模拟的 JaegerTracer 给出了 null..

我使用过JUnit5和SpringBoot 2.7.6。

请求检查并提出建议..

服务


@Service
public class RestClientHeroMovieService {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private RestClientService restClientService;

    @Autowired
    private StatisticsConfig statisticsConfig;

    @Autowired
    private JaegerTracer jaegerTracer;

    @Value("${test.value}")
    private String testValue;

    public HeroMovie getHeroMovieDetails(String heroName) throws URISyntaxException {

        Span span = jaegerTracer.buildSpan("getHeroMovieDetails").start(); //giving NPE as jaegerTracer is null

        Span spanHeroMovie = jaegerTracer.buildSpan("spanHeroMovie").asChildOf(span).start();
        String endpoint = "http://localhost:9050/orders/v1/getHeroDetails/"+heroName;

        HeroMovie heroMovie = restTemplate.getForObject(endpoint,HeroMovie.class);
        spanHeroMovie.finish();

        endpoint = "http://localhost:9050/orders/v1/getMoviesOfHero/"+heroName;
        URI uri = new URI(endpoint);

        Span spanListMovie = jaegerTracer.buildSpan("spanListMovie").asChildOf(span).start();
        List<Movie> listMovie = restTemplate.exchange(uri, HttpMethod.GET, null, new ParameterizedTypeReference<List<Movie>>(){}).getBody();
        heroMovie.setMovies(listMovie);
        spanListMovie.finish();

        heroMovie.setPlatforms(statisticsConfig.getPlatforms());
        heroMovie.setBrowsers(statisticsConfig.getBrowsers());
        heroMovie.setSystems(statisticsConfig.getSystems());

        heroMovie.setSomeTestValue(testValue);

        heroMovie.setPet(getPet(heroMovie.getHeroName()));

        restClientService.clearAllCache();

        span.finish();
        return heroMovie;

    }

JUnit


@ExtendWith({SpringExtension.class})  
@ExtendWith({MockitoExtension.class})  
@SpringBootTest(classes = {RestClientHeroMovieServiceTest.class, StatisticsConfig.class}) 
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
@EnableConfigurationProperties(value = {StatisticsConfig.class})
@TestPropertySource("classpath:test.properties")
public class RestClientHeroMovieServiceTest {

    private final String testValue = "aaa";

    @InjectMocks
    @Spy
    private RestClientHeroMovieService restClientHeroMovieService;
    @Mock
    private RestTemplate restTemplate;
    @Mock
    private RestClientService restClientService;

    @Mock
    private StatisticsConfig statisticsConfig;

    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
    private JaegerTracer jaegerTracer;

    @BeforeEach
    public void init() {
        ReflectionTestUtils.setField(restClientHeroMovieService, "testValue", testValue);
        MockitoAnnotations.openMocks(this);
    }

    @Test
    @SneakyThrows
    public void testGetHeroMovieDetails() {

        HeroMovie heroMovie = getHeroMovie();

        restClientHeroMovieService.setJaegerTracer(jaegerTracer);
        Mockito.when(jaegerTracer.buildSpan(Mockito.anyString()).start())
                .thenReturn(Mockito.mock(JaegerSpan.class));

        Mockito.doReturn(heroMovie)
                .when(restTemplate)
                .getForObject(Mockito.anyString(), Mockito.any());

        List<Movie> listMovie = getListMovie();
        ResponseEntity<List<Movie>> responseEntityListMovie = ResponseEntity.ok(listMovie);

        Mockito.doReturn(responseEntityListMovie)
                .when(restTemplate)
                .exchange(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(ParameterizedTypeReference.class));

        Mockito.doNothing()
                .when(restClientService)
                .clearAllCache();

        Assertions.assertTrue(heroMovie.getHeroName().equalsIgnoreCase("test") && heroMovie.getMovies().get(0).getMovieName().equalsIgnoreCase("TestM") && heroMovie.getSomeTestValue().equalsIgnoreCase(testValue));

    }


spring-boot mockito junit5 jaeger
1个回答
0
投票

如果可能的话,您应该依赖抽象而不是具体的类。

JaegerTracer
是一个实现
io.opentracing.Tracer
接口的类。你的类应该自动装配一个
Tracer
bean。

Mockito 仍然必须遵循 JVM 的规则,这意味着诸如以下的语句:

Mockito.when(jaegerTracer.buildSpan(Mockito.anyString()).start())
        .thenReturn(Mockito.mock(JaegerSpan.class));
在进入

buildSpan 方法之前,

必须
仍然调用 start
when
(Java 中的参数会被急切求值)。

最后,不要将 Mockito 测试与 Spring 测试混合在一起;它们的注释不能很好地混合,这很可能就是自动装配字段为空的原因。决定一种方法并仅使用一种:要么在应用程序上下文中使用 Spring 注册 bean(和模拟 bean;用

@MockBean
定义)并自动装配它们,要么使用 Mockito 创建模拟实例并注入它们(用
@Mock
 @InjectMocks
)。

© www.soinside.com 2019 - 2024. All rights reserved.