Mockito为什么说我的存根是不必要的

huangapple go评论75阅读模式
英文:

Why Mockito says that my stubbings are unnecessary

问题

以下是要翻译的代码部分:

StudentServiceTests

package com.mdv.secondservice;

import com.mdv.secondservice.api.dto.ThirdServiceStudentDto;
import com.mdv.secondservice.api.proxy.ThirdServiceProxy;
import com.mdv.secondservice.db.model.Student;
import com.mdv.secondservice.db.repository.StudentRepository;
import com.mdv.secondservice.service.StudentService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.convert.ConversionService;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.when;

@SpringBootTest
@ExtendWith(MockitoExtension.class)
public class StudentServiceTests {
    @Mock
    private StudentRepository studentRepository;

    @Mock
    private ConversionService conversionService;

    @Mock
    private ThirdServiceProxy thirdServiceProxy;

    @InjectMocks
    private StudentService studentService;

    private Student student;
    private ThirdServiceStudentDto thirdServiceStudentDto;

    @BeforeEach
    void init() {
        final String middleName = "middleName";
        final String lastName = "lastName";
        student = Student.builder()
                .middleName(middleName)
                .lastName(lastName)
                .build();
        thirdServiceStudentDto = new ThirdServiceStudentDto(lastName);
    }

    @Test
    void createStudent_StudentWasCreated() {
        when(conversionService.convert(any(Student.class), same(ThirdServiceStudentDto.class)))
                .thenReturn(thirdServiceStudentDto);
        when(thirdServiceProxy.createStudent(any(ThirdServiceStudentDto.class))).thenReturn(student);
        when(studentService.createStudent(student)).thenReturn(student);

        Student returnedStudent = studentService.createStudent(student);

        assertThat(returnedStudent).isEqualTo(student);
    }
}

StudentService

package com.mdv.secondservice.service;

import com.mdv.secondservice.api.dto.ThirdServiceStudentDto;
import com.mdv.secondservice.api.proxy.ThirdServiceProxy;
import com.mdv.secondservice.db.model.Student;
import com.mdv.secondservice.db.repository.StudentRepository;
import feign.FeignException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.convert.ConversionService;
import org.springframework.stereotype.Service;

@Service
@Slf4j
@RequiredArgsConstructor
public class StudentService {
    private final StudentRepository studentRepository;
    private final ConversionService conversionService;
    private final ThirdServiceProxy thirdServiceProxy;

    public Student createStudent(Student student) throws FeignException.InternalServerError {
        ThirdServiceStudentDto thirdServiceStudentDto =
                conversionService.convert(student, ThirdServiceStudentDto.class);
        Student createdStudent = thirdServiceProxy.createStudent(thirdServiceStudentDto);

        createdStudent.setMiddleName(student.getMiddleName());
        studentRepository.save(createdStudent);

        return createdStudent;
    }
}

请注意,这是您提供的代码的翻译版本,没有其他内容。如果您需要更多帮助或有其他问题,请随时告诉我。

英文:

I'm trying to mock Spring's ConversionService so convert() method always returns the dto created by me, but Mockito says that my stubbings are unnecessary and mocked ConversionService returns null.

Here's the code:

StudentServiceTests

package com.mdv.secondservice;

import com.mdv.secondservice.api.dto.ThirdServiceStudentDto;
import com.mdv.secondservice.api.proxy.ThirdServiceProxy;
import com.mdv.secondservice.db.model.Student;
import com.mdv.secondservice.db.repository.StudentRepository;
import com.mdv.secondservice.service.StudentService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.convert.ConversionService;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.when;

@SpringBootTest
@ExtendWith(MockitoExtension.class)
public class StudentServiceTests {
    @Mock
    private StudentRepository studentRepository;

    @Mock
    private ConversionService conversionService;

    @Mock
    private ThirdServiceProxy thirdServiceProxy;

    @InjectMocks
    private StudentService studentService;

    private Student student;
    private ThirdServiceStudentDto thirdServiceStudentDto;

    @BeforeEach
    void init() {
        final String middleName = "middleName";
        final String lastName = "lastName";
        student = Student.builder()
                .middleName(middleName)
                .lastName(lastName)
                .build();
        thirdServiceStudentDto = new ThirdServiceStudentDto(lastName);
    }

    @Test
    void createStudent_StudentWasCreated() {
        when(conversionService.convert(any(Student.class), same(ThirdServiceStudentDto.class)))
                .thenReturn(thirdServiceStudentDto);
        when(thirdServiceProxy.createStudent(any(ThirdServiceStudentDto.class))).thenReturn(student);
        when(studentService.createStudent(student)).thenReturn(student);

        Student returnedStudent = studentService.createStudent(student);

        assertThat(returnedStudent).isEqualTo(student);
    }
}

StudentService

package com.mdv.secondservice.service;

import com.mdv.secondservice.api.dto.ThirdServiceStudentDto;
import com.mdv.secondservice.api.proxy.ThirdServiceProxy;
import com.mdv.secondservice.db.model.Student;
import com.mdv.secondservice.db.repository.StudentRepository;
import feign.FeignException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.convert.ConversionService;
import org.springframework.stereotype.Service;

@Service
@Slf4j
@RequiredArgsConstructor
public class StudentService {
    private final StudentRepository studentRepository;
    private final ConversionService conversionService;
    private final ThirdServiceProxy thirdServiceProxy;

    public Student createStudent(Student student) throws FeignException.InternalServerError {
        ThirdServiceStudentDto thirdServiceStudentDto =
                conversionService.convert(student, ThirdServiceStudentDto.class);
        Student createdStudent = thirdServiceProxy.createStudent(thirdServiceStudentDto);

        createdStudent.setMiddleName(student.getMiddleName());
        studentRepository.save(createdStudent);

        return createdStudent;
    }
}

It seems like I messed up with matchers in the first when call. I know I didn't mock StudentRepository, I will fix that later. The problem is that conversionService.convert(...) returns null when called in StudentService.createStudent method.

UPD (added Mockito error):


java.lang.NullPointerException
at com.mdv.secondservice.service.StudentService.createStudent(StudentService.java:26)
at com.mdv.secondservice.StudentServiceTests.createStudent_StudentWasCreated(StudentServiceTests.java:59)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:686)
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:212)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:208)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:137)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:71)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$5(DefaultLauncher.java:211)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:132)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
Suppressed: org.mockito.exceptions.misusing.UnnecessaryStubbingException: 
Unnecessary stubbings detected.
Clean & maintainable test code requires zero unnecessary code.
Following stubbings are unnecessary (click to navigate to relevant line of code):
1. -> at com.mdv.secondservice.StudentServiceTests.createStudent_StudentWasCreated(StudentServiceTests.java:56)
2. -> at com.mdv.secondservice.StudentServiceTests.createStudent_StudentWasCreated(StudentServiceTests.java:58)
Please remove unnecessary stubbings or use 'lenient' strictness. More info: javadoc for UnnecessaryStubbingException class.
at org.mockito.junit.jupiter.MockitoExtension.afterEach(MockitoExtension.java:181)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeAfterEachCallbacks$11(TestMethodTestDescriptor.java:255)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeAllAfterMethodsOrCallbacks$12(TestMethodTestDescriptor.java:271)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeAllAfterMethodsOrCallbacks$13(TestMethodTestDescriptor.java:271)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeAllAfterMethodsOrCallbacks(TestMethodTestDescriptor.java:270)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeAfterEachCallbacks(TestMethodTestDescriptor.java:254)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:143)
... 41 more

答案1

得分: 1

当你模拟一切时,你不需要Spring Boot上下文。
你可以删除@SpringBootTest
然后你的示例应该可以运行。

否则,你可以用@ExtendWith(SpringExtension.class)替换@ExtendWith(MockitoExtension.class)

英文:

When you mock everything, you dont need the spring boot context.
You can delete the @SpringBootTest.
And your example should run.

Otherwise you can replace @ExtendWith(MockitoExtension.class)
with @ExtendWith(SpringExtension.class).

huangapple
  • 本文由 发表于 2020年7月22日 23:04:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/63037395.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定