简体   繁体   中英

Running junit5 test with Mockito throw “InvocationTargetException” and does not complete MockMvc perform() method call

I was practicing Junit5 with Mockito and doing parameterized testing on spring boot application Postman request and responses tests show no issues with my code, but I could not accomplish with a junit5 test. I get " InvoicationTargetException " whenever I do MockMvc perform(..) method call. I have googled for possible solutions but I did not find what I was looking. Initially, I was having issue cause I was not mocking the service, but and this problem started showing up. I find it difficult to debug the test with breakpoints, and sometimes debugging does not step in to a method call, and difficult to understand the problem.

I could not recreate another scenario also where MockMvc .perform task gets completed, but MvcResult would be empty, and I get an error "Unparsable json string" . I do appreciate some directions on running the following junit test successfully.

Entity

Book : id(Integer), title(String),pubYear(String), author(Author)
Author : id(Integer), firstName(String), lastName(String), books(List)
AuthorRepository

@Repository
public interface AuthorRepository 
                 extends CrudRepository<Author, Integer>{
    @Query("select b from Author b where b.firstName= ?1 and b.lastName = ?2") 
    public Author findAuthorByName(String firstName, String lastName);
}

AuthorController

@RestController
@RequestMapping(value="/authors")
public class AuthorController {

    @Autowired
    private AuthorService authorService;
..................
    @GetMapping(path = "/books/{first}/{last}")
    public Book getBooksByAuthorName(@PathVariable String first, @PathVariable String last) {
        Book book = this.authorService.getBooksByAuthorName(first, last);
        return book;
    }
}

AuthorService

@Service
public class AuthorService {

    @Autowired
    private AuthorRepository authorRepository;
    @Autowired
    private BookService bookService;
 .................
    public Book getBookByAuthorName(String first, String last) {
    Author author = this.authorRepository.findAuthorByName(first, last);
    Book b = author.getBooks().get(0);
    return b;
}

AuthorControllerTest

@AutoConfigureMockMvc
public class AuthorControllerTest {
    @Autowired
    private MockMvc mockMvc;
    @Mock
    private AuthorService authorService;

    //input for parameterized testing, currently only one test sample
    public static Collection<Object[]> input() {
        return Arrays.asList(new Object[][] {
            {"Test-1",
            "John",
            "Banville",
            "{ \"id\":1, \"title\":\"Eclipse\", \"pubYear\":\"2000\", \"author\":{\"id\":1, \"firstName\":\"john\", \"lastName\":\"banville\"}}"
            }      
        });
    }
    @BeforeEach
    public void initMOcks() {
        MockitoAnnotations.initMocks(this);
    }
     
    @ParameterizedTest
    @MethodSource("input")
    public void testGetBooksByAuthor(String testId, String firstName, String lastName, 
                        String expectedResponse) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        Book book = null;
        if(expectedResponse != null) {
            book = mapper.readValue(expectedResponse, Book.class);
        }

        doReturn(book).when(authorService).getBookByAuthorName(firstName,lastName);
        MvcResult result = mockMvc.perform(
                MockMvcRequestBuilders.get("/authors/books/{first}/{last}", firstName,lastName))
                .andReturn();
        System.out.println(testId + "Result: " + result.getResponse().getContentAsString());
        System.out.println(testId + "Expect: " + expectedResponse );
        JSONAssert.assertEquals(expectedResponse, result.getResponse().getContentAsString(), true);

    }
}

As @Kathrin Geilmann suggested I added @MockBean. I have [read][1] this is not mocking, but I tried that I got

.UnsatisfiedDependencyException: Error creating bean with name 'authorController': Unsatisfied dependency expressed through constructor parameter 0; nested exception

then I added @MockBean for each nested dependencies. Below the arrow direction shows where those dependency beans are injected in the constructors in the classes I have.
AuthorController <-- AuthorService <-- (AuthorRepository, BookService)<-- Bookrepository

    @MockBean
    private AuthorService authorService;
    @MockBean
    private AuthorRepository authorRepository;
    @MockBean
    private BookService bookService;

Why BookReqpository is not considered "Unsatisfied dependency" ? I run the test I get

NullInsteadOfMockException, Argument passed to when() is null;

This is the line of the code from original post

 doReturn(book).when(authorService).getBooksByAuthorName(firstName,lastName);

This is where I switched @MockBean to @Mock for authorService but I got the same error. So I switched back to @MockBean I have finally changed the test class annotation to use @WebMvcTest. This made the test run without any issue, and I also removed @AutoConfigureMockMvc did not create any problem.

@WebMvcTest
public class AuthorControllerTest {

Though I can run the test now, but I do not think I done any mocking, and I have read that @MockBean is not mocking. [1]: https://www.baeldung.com/java-spring-mockito-mock-mockbean

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM