Spring Boot Unit Testing - Test fails complaining about not having an "entityManagerFactory" bean defined
Asked Answered
R

6

7

I'm trying to write a unit test for a Controller in a Spring Boot application. The application runs smoothly, my problem is with running its tests.

Here is the test code:

@RunWith(SpringRunner.class)
@WebMvcTest(MyController.class)
@AutoConfigureTestEntityManager
public class MyControllerTest {

@Autowired
private MockMvc mockMvc;

@Mock
private MyRepository myRepository;

@Mock
ZendeskNotifier zendeskNotifier;

@Mock
ActivityLogger activityLogger;

@Before
public void setUp() throws Exception {
    MockitoAnnotations.initMocks(this);
}

@Test
public void cannotSendFooWithoutMessageBody() throws Exception {
    this.mockMvc.perform(post("/api/v1/foo/1/send"))
            .andDo(print())
            .andExpect(status().is4xxClientError())
            .andExpect(content().string(containsString("The message body cannot be empty.")));
}
}

When I try running it I get:

***************************
APPLICATION FAILED TO START
***************************

Description:

Field jobEventRepository in foo.bar.util.memsource.svc.MemsourceEventProcessor required a bean named 'entityManagerFactory' that could not be found.


Action:

Consider defining a bean named 'entityManagerFactory' in your configuration.

And that feels weird to me, since I'm providing the AutoConfigureTestEntityManager annotation and would expect all the EntityManager-related stuff to be in place.

Rank answered 28/6, 2017 at 17:35 Comment(2)
Hi Alvaro, did you manage to solve this eventually? Thanks.Fiftieth
Hi @Daniel, actually, no. :( I've already left that job and as far as I know they never got it working (they never really were into the TDD boat anyway)Rank
M
5

I found out that there is an Annotation you can use to add JPA-Support to your WebMVCTest (@AutoConfigureDataJpa)

@ContextConfiguration(classes = { SurchargesTestConfiguration.class })
@WebMvcTest(SurchargesApiController.class)
@AutoConfigureDataJpa
@ActiveProfiles("local")
class SurchargesApiControllerTest {

    @Autowired
    private MockMvc mvc;

    @Test
    void testNotFound() throws Exception {
        mvc.perform(get("/surcharges/marketnumber") //
                .headers(getDefaultHeaders())) //
                .andExpect(status().isNotFound());
    }
}

Marasco answered 10/11, 2022 at 14:19 Comment(0)
T
3

If Google brought you here and you're using Spring Boot, you may need to add @DataJpaTest to your test class. It's found in org.springframework.boot:spring-boot-test-autoconfigure. You may also discover upon rerunning that you need to declare a dependency on org.hibernate:hibernate-validator.

Tumulus answered 19/3, 2018 at 18:52 Comment(2)
But why do I need to add @DataJpaTest to a controller test? I've created completely empty controller with completely empty test and it still fails with "NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available". Why? :( Edit: also, you can't have both \@WebMvcTest and \@DataJpaTest.Slenderize
@Dalibor Thanks for that comment about the empty test - it helped me figure out the answer, which is that your application's configuration (and mine) were being found and used by the unit tests. I posted an answer with a full explanation, and ways to fix.Scherzo
S
3

Spring Boot is loading your application's configuration, causing your data layer to be initialized.

Excerpt from Spring Boot's docs, Detecting Test Configuration:

Spring Boot’s @*Test annotations search for your primary configuration automatically whenever you do not explicitly define one.

The search algorithm works up from the package that contains the test until it finds a class annotated with @SpringBootApplication or @SpringBootConfiguration. As long as you structured your code in a sensible way, your main configuration is usually found.

When the scanning hits your main class it is likely finding an annotation like @EnableJpaRepositories, which initializes your data layer and thus requires the entity manager factory. (You may see other side effects too, like Hibernate initializing your in-memory database if your application uses one.)

As other answers suggest, you could initialize the data layer, or try to wire/mock the missing beans. But since you aren't testing the data layer here it would be better to control the test's configuration.

The docs suggest some solutions:

  1. Move @EnableJpaRepositories from the main class to a config class in child package. It will get scanned by the application (from the top package down) but not by the unit tests. This is discussed in the section User Configuration and Slicing.

  2. Add a nested @Configuration class to override the configuration used by the unit test.

The first one seems like a good rule to follow in general. Other annotations like @EnableBatchProcessing and @EnableScheduling can be treated the same way, which will speed up your unit tests.

Scherzo answered 8/10, 2019 at 17:27 Comment(1)
Note that if you move @EnableJpaRepositories to a config class you will probably run into a different problem when you run the app, which is your repositories suddenly not autowiring. Solution here: https://mcmap.net/q/166662/-can-39-t-autowire-repository-annotated-interface-in-spring-bootScherzo
F
1

Inject Spring's TestEntityManager in your mockito test class.

@Autowired
private TestEntityManager entityManager;

You are already using @AutoConfigureTestEntityManager on the test class to auto configure this test entity manager. So you don't have to do anything else in the config file.

Faqir answered 28/6, 2017 at 18:52 Comment(1)
I tried autowiring both TestEntityManager and also EntityManagerFactory and got the exact same result as described above. :(Rank
C
0

you need to configure entityManagerFactory, you can refer bellow code

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="packagesToScan" value="org.demo.test.entity" />
<property name="dataSource" ref="dataSource" />

<property name="jpaProperties">
    <props>
        <prop key="hibernate.show_sql">true</prop>
        <prop key="hibernate.hbm2ddl.auto">create</prop>
        <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
    </props>
</property>

<property name="persistenceProvider">
    <bean class="org.hibernate.jpa.HibernatePersistenceProvider">
</bean>
</property>

</bean>
Crimple answered 28/6, 2017 at 18:8 Comment(0)
W
0

Move @EnableJpaRepositories from the main class to a config class in a child package. It will get scanned by the application (from the top package down) but not by the unit tests.

@Configuration
@EnableJpaRepositories(
    value = "com.company.repository"
)
public class JpaConfig {
}
Wooten answered 15/10, 2021 at 22:0 Comment(1)
Please tend to give an explanation along with code as well as a good practice and for better understanding.Bowls

© 2022 - 2024 — McMap. All rights reserved.