@DataJpaTest needing a class outside the test

robert trudel picture robert trudel · Dec 11, 2016 · Viewed 12.2k times · Source

In a SpringBoot application, I would like to do some test about the repository layer.

@RunWith(SpringRunner.class)
@DataJpaTest
public class VisitRepositoryTest {

     @Autowired
     private TestEntityManager entityManager;

     @Autowired
     private VisitRepository visitRepository;

     ...
}

When I try to run test from VisitRepositoryTest, I get an error about DefaultConfigService

Field defaultConfigService in com.norc.Application required a bean of type 'com.norc.service.DefaultConfigService' that could not be found.

So this needs to run the Application?

I tried to put a bean of DefaultConfigService in VisitRepositoryTest, but it's not allowed.

This class is used in my app

@EntityScan(basePackageClasses = {Application.class, Jsr310JpaConverters.class})
@SpringBootApplication
@EnableScheduling
public class Application implements SchedulingConfigurer {

      @Autowired
      private DefaultConfigService defaultConfigService;
      ...
}

How to manage that?


Edit

In my Application, I use this class in a cron tab:

@Service
public class DefaultConfigServiceImpl implements DefaultConfigService {

    private final DefaultConfigRepository defaultConfigRepository;

    @Autowired
    public DefaultConfigServiceImpl(final DefaultConfigRepository defaultConfigRepository) {
         this.defaultConfigRepository = defaultConfigRepository;
    }
}

Answer

Stephane Nicoll picture Stephane Nicoll · Dec 11, 2016

The problem is that your @SpringBootApplication has some additional configuration regarding scheduling and by adding that there and not having a custom @SpringBootConfiguration for your test, such scheduling requirement becomes mandatory for everything.

Let's take a step back. When you add @DataJpaTest, Spring Boot needs to know how to bootstrap your application context. It needs to find your entities and your repositories. Slice tests will recursively search for a @SpringBootConfiguration: first in the package of your actual test, then the parent, then the parent and if it doesn't find one it will throw an exception.

@SpringBootApplication is a @SpringBootConfiguration so if you don't do anything special, slice tests will use your app as the source for configuration (which is IMO, an excellent default).

Slice tests do not blindly start you app (otherwise that wouldn't be slicing) so what we do is disable auto-configuration and customize component scan for the task at hand (only scanning entities and repositories and ignoring all the rest when you use @DataJpaTest). That's a problem for you since the application configuration is applied and the scheduling stuff should be available. But dependent beans aren't scanned.

In your case, if you want to use slicing the scheduling configuration should move to a SchedulingConfiguration or something (it won't be scanned with slicing as explained above). Regardless, I think it's cleaner to separate a SchedulingConfigurer implementation anyway. If you do that, you'll notice the error will go away.

Let's assume now that you want for that particular test that FooService is also available. Rather than enabling component scan as dimitrisli suggested (that's basically disabling slicing for your configuration), you can just import the missing class

@RunWith(SpringRunner.class)
@DataJpaTest
@Import(FooService.class)
public class VisitRepositoryTest {
  ...
}