Home > Blockchain >  @WebMvcTest with @Import does not work. Test context always asks for @Repository beans
@WebMvcTest with @Import does not work. Test context always asks for @Repository beans

Time:09-12

Using Spring Boot 2.7.3 I can not create a simple integration test for my API using @WebMvcTest.

Here is my setup:

// GameServerApplicationTests.kt
@SpringBootTest
class GameServerApplicationTests {
    @Test
    fun contextLoads() { }
}
// CraftService.kt
@Service
class CraftService {
    fun getAll(): List<String> {
        return listOf("foo", "bar")
    }
}
// CraftApiTest.kt
@WebMvcTest
@Import(value = [CraftService::class])
class CraftApiTest {
    @Autowired
    private lateinit var testRestTemplate: TestRestTemplate

    @Test
    fun `should do accept craft all endpoint`() {
        val response = testRestTemplate.getForEntity("/craft/all", String::class.java)
        assertThat(response.statusCode).isEqualTo(HttpStatus.OK)
    }
}

When I run the test I see this exception:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'itemRepository' defined in com.gameserver.item.ItemRepository defined in @EnableJpaRepositories declared on GameServerApplication: Cannot create inner bean '(inner bean)#3fba233d' of type [org.springframework.orm.jpa.SharedEntityManagerCreator] while setting bean property 'entityManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#3fba233d': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available

I have no idea why it is looking for the itemRepository bean at all. I never asked for that.

I then added this

@WebMvcTest
@ComponentScan(excludeFilters = [ComponentScan.Filter(Repository::class)]) // <<
@Import(value = [CraftService::class])

Which resulted in this exception:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'playerRepository' defined in com.gameserver.player.PlayerRepository defined in @EnableJpaRepositories declared on GameServerApplication: Cannot create inner bean '(inner bean)#30c1da48' of type [org.springframework.orm.jpa.SharedEntityManagerCreator] while setting bean property 'entityManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#30c1da48': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available

Which confuses me even more. I explictly excluded all @Repository beans - but it just skipped ItemRepository and then asked for PlayerRepository now.

I am totally lost and have no idea why I am not able to setup a simple integration test for my API endpoint.

EDIT #1:

Other tests run just fine:

enter image description here

EDIT #2:

I tried to use a @Configuration bean for @Import.

// CraftApiTestConfiguration
@Configuration
class CraftApiTestConfiguration {
    @Bean
    fun getCraftService(): CraftService {
        return CraftService()
    }
}
// CraftApiTest.kt
@WebMvcTest
@Import(CraftApiTestConfiguration::class)
class CraftApiTest { // ... }

That did not help either. It just gave me the second exception mentioned above (the one asking for playerRepository)

CodePudding user response:

I'll try to answer although without seeing the actual code it might not be correct.

So @WebMvcTest loads a "slice" of your application with all the beans annotated with @RestControllers. It doesn't load @Service or @Repository annotated beans.

When you run the test with @WebMvcTest annotation it will load all the controllers, and if, by accident the controller references others than the reference on the service (here I can't say for sure what it is), you might end up loading the stuff that you don't actually need.

Now when you use @WebMvcTest there are two things you can/should do:

  1. Work with MockMvc instead of rest template that queries a web server, its not a full-fledged web layer test anyway.

  2. Try using @WebMvcTest with your controller only:

@WebMvcTest(CraftApisController.class)

Also instead of injecting the real implementation of service, you can use @MockBean so that the real service implementation will be covered by a regular unit test (without spring at all, just plain JUnit/Mockito) and this test could check that your annotations are defined correctly

  • Related