可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm new to frameworks (just passed the class) and this is my first time using springboot.
I'm trying to run a simple Junit test to see if my CrudRepositories are indeed working.
The error I keep getting is:
Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=...) with your test
java.lang.IllegalStateException
doesn't spring boot configure itself?
My Test Class
@RunWith(SpringRunner.class)
@DataJpaTest
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class JpaTest {
@Autowired
private AccountRepository repository;
@After
public void clearDb(){
repository.deleteAll();
}
@Test
public void createAccount(){
long id = 12;
Account u = new Account(id,"Tim Viz");
repository.save(u);
assertEquals(repository.findOne(id),u);
}
@Test
public void findAccountByUsername(){
long id = 12;
String username = "Tim Viz";
Account u = new Account(id,username);
repository.save(u);
assertEquals(repository.findByUsername(username),u);
}
My Spring boot application starter
@SpringBootApplication
@EnableJpaRepositories(basePackages = {"domain.repositories"})
@ComponentScan(basePackages = {"controllers","domain"})
@EnableWebMvc
@PropertySources(value {@PropertySource("classpath:application.properties")})
@EntityScan(basePackages={"domain"})
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
}
}
My Repository
public interface AccountRepository extends CrudRepository<Account,Long> {
public Account findByUsername(String username);
}
}
thanks in advance
回答1:
Indeed, Spring Boot does set itself up for the most part. You can probably already get rid of a lot of the code you posted, especially in Application
.
I wish you had included the package names of all your classes, or at least the ones for Application
and JpaTest
. The thing about @DataJpaTest
and a few other annotations is that they look for a @SpringBootConfiguration
annotation in the current package, and if they cannot find it there, they traverse the package hierarchy until they find it.
For example, if the fully qualified name for your test class was com.example.test.JpaTest
and the one for your application was com.example.Application
, then your test class would be able to find the @SpringBootApplication
(and therein, the @SpringBootConfiguration
).
If the application resided in a different branch of the package hierarchy, however, like com.example.application.Application
, it would not find it.
Example
Consider the following Maven project:
my-test-project
+--pom.xml
+--src
+--main
+--com
+--example
+--Application.java
+--test
+--com
+--example
+--test
+--JpaTest.java
And then the following content in Application.java
:
package com.example;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Followed by the contents of JpaTest.java
:
package com.example.test;
@RunWith(SpringRunner.class)
@DataJpaTest
public class JpaTest {
@Test
public void testDummy() {
}
}
Everything should be working. If you create a new folder inside src/main/com/example
called app
, and then put your Application.java
inside it (and update the package
declaration inside the file), running the test will give you the following error:
java.lang.IllegalStateException: Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=...) with your test
回答2:
Configuration is attached to the application class, so the following will set up everything correctly:
@SpringBootTest(classes = Application.class)
Example from the JHipster project here.
回答3:
It is worth to check if you have refactored package name of your main class annotated with @SpringBootApplication
. In that case the testcase should be in an appropriate package otherwise it will be looking for it in the older package . this was the case for me.
回答4:
In addition to what Thomas Kåsene said, you can also add
@SpringBootTest(classes=com.package.path.class)
to the test annotation to specify where it should look for the other class if you didn't want to refactor your file hierarchy. This is what the error message hints at by saying:
Unable to find a @SpringBootConfiguration, you need to use
@ContextConfiguration or @SpringBootTest(classes=...) ...
回答5:
The test slice provided in Spring Boot 1.4 brought feature oriented test capabilities.
For example,
@JsonTest provides a simple Jackson environment to test the json serialization and deserialization.
@WebMvcTest provides a mock web environment, it can specify the controller class for test and inject the MockMvc in the test.
@WebMvcTest(PostController.class)
public class PostControllerMvcTest{
@Inject MockMvc mockMvc;
}
@DataJpaTest will prepare an embedded database and provides basic JPA environment for the test.
@RestClientTest provides REST client environment for the test, esp the RestTemplateBuilder etc.
These annotations are not composed with SpringBootTest, they are combined with a series of AutoconfigureXXX
and a @TypeExcludesFilter
annotations.
Have a look at @DataJpaTest
.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@BootstrapWith(SpringBootTestContextBootstrapper.class)
@OverrideAutoConfiguration(enabled = false)
@TypeExcludeFilters(DataJpaTypeExcludeFilter.class)
@Transactional
@AutoConfigureCache
@AutoConfigureDataJpa
@AutoConfigureTestDatabase
@AutoConfigureTestEntityManager
@ImportAutoConfiguration
public @interface DataJpaTest {}
You can add your @AutoconfigureXXX annotation to override the default config.
@AutoConfigureTestDatabase(replace=NONE)
@DataJpaTest
public class TestClass{
}
Let's have a look at your problem,
- Do not mix
@DataJpaTest
and @SpringBootTest
, as said above @DataJpaTest
will build the configuration in its own way(eg. by default, it will try to prepare an embedded H2 instead) from the application configuration inheritance. @DataJpaTest
is designated for test slice.
- If you want to customize the configuration of
@DataJpaTest
, please read this official blog entry from Spring.io for this topic,(a little tedious).
- Split the configurations in
Application
into smaller configurations by features, such as WebConfig
, DataJpaConfig
etc. A full featured configuration(mixed web, data, security etc) also caused your test slice based tests to be failed. Check the test samples in my sample.
回答6:
I think that the best solution for this issue is to align your tests folders structure with the application folder structure.
I had the same issue which was caused by duplicating my project from a different folder structure project.
if your test project and your application project will have the same structure you will not be required to add any special annotations to your tests classes and everything will work as is.
回答7:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureWebMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@DataJpaTest
@SpringBootTest
@AutoConfigureWebMvc
public class RepoTest {
@Autowired
private ThingShiftDetailsRepository thingShiftDetailsRepo;
@Test
public void findThingShiftDetails() {
ShiftDetails details = new ShiftDetails();
details.setThingId(1);
thingShiftDetailsRepo.save(details);
ShiftDetails dbDetails = thingShiftDetailsRepo.findByThingId(1);
System.out.println(dbDetails);
}
}
Above annotations worked well for me. I am using spring boot with JPA.