In tests i can add any bean (using static nested configuration class). but how can i add spring-data repositories? i can't return then as new bean because i can't instantiate them - they are interfaces
#RunWith(SpringRunner.class)
#DataMongoTest
//#SpringBootTest // or this annotation
public class JTest {
#Configuration
static class Config {
static class TestEntity {
String id;
}
interface TestRepository extends ReactiveMongoRepository<TestEntity, String> {}
}
#Autowired Config.TestRepository testRepository;
#Test
public void test() {}
}
running with #DataMongoTest gives me
Caused by: java.lang.IllegalStateException: Unable to retrieve #EnableAutoConfiguration base packages
running with #SpringBootTest gives:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'xxx.JTest$Config$TestRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
how can i add new repositories in tests?
Spring doesn't pick up nested interface repository (and instantiate a bean) by default. To enable, see:
#RunWith(SpringRunner.class)
#DataMongoTest
#EnableMongoRepositories(considerNestedRepositories = true)
public class JobTest {
#TestConfiguration
static class Config {
static class TestEntity {
String id;
}
....
Internally, Spring registers a bean with new SimpleMongoRepository<T, ID>(..) if none other specified.
Edit
Just realized you are using reactive Mongo. So switch to EnableReactiveMongoRepositories(..) instead.
Related
I have an application that works fine in Spring Boot 2.3.8 but the #RestClientTests fails with 2.4.2 because the test objects can not be instantiated because there's no bean of the #ConfigurationProperties (which is created by the #TestConfiguration).
How do I have to change my code so it works with 2.4.x?
Code is:
#Configuration
#ConfigurationProperties(prefix = "tyntec.routetest.dsidr")
#Data
#Validated
public class DynamicSenderIdReplacementClientConfiguration {
#NotBlank
private String baseUrl;
#NotBlank
private String dsidrPath;
}
#Component
#RequiredArgsConstructor
public class DynamicSenderIdReplacementClient {
private final DynamicSenderIdReplacementClientConfiguration configuration;
}
#ExtendWith(SpringExtension.class)
#RestClientTest(DynamicSenderIdReplacementClient.class)
#AutoConfigureWebClient(registerRestTemplate = true)
class DynamicSenderIdReplacementClientWebTest {
#Autowired
private DynamicSenderIdReplacementClient cut;
#TestConfiguration
static class testConfiguration {
#Bean
#Primary
public DynamicSenderIdReplacementClientConfiguration provideConfig() {
return new DynamicSenderIdReplacementClientConfiguration() {
{
setBaseUrl(BASE_URL);
setDsidrPath(DSIDR_PATH);
}
};
}
}
This works in 2.3.8 but fails in 2.4.2 with
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.tyntec.routetesting.client.itest.clients.DynamicSenderIdReplacementClientConfiguration' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
Turns out, #RestClientTest works as advertised and inhibits the beans in #TestConfiguration:
Using this annotation will disable full auto-configuration and instead
apply only configuration relevant to rest client tests (i.e. Jackson
or GSON auto-configuration and #JsonComponent beans, but not regular
#Component beans).
Using #Import helps.
#RestClientTest(DynamicSenderIdReplacementClient.class)
#AutoConfigureWebClient(registerRestTemplate = true)
#Import(DynamicSenderIdReplacementClientWebTest.testConfiguration.class)
class DynamicSenderIdReplacementClientWebTest {
I am writing the integration tests with #WebFluxTest for my #RestController.
Here are my classes:
#RestController
#RequestMapping("/usager")
public class UsagerController {
#Autowired
private UsagerService usagerService;
#GetMapping
public Usager getUsager() {
return usagerService.create();
}
}
#Service
public class UsagerService implements CrudService<Usager, Integer> {
#Autowired
private UsagerRepository usagerRepository;
#Override
public JpaRepository<Usager, Integer> getRepository() {
return usagerRepository;
}
#Override
public Usager create() {
return new Usager();
}
}
#Repository
public interface UsagerRepository extends JpaRepository<Usager, Integer>, JpaSpecificationExecutor<Usager> {
}
#ExtendWith(SpringExtension.class)
#WebFluxTest(UsagerController.class)
#Import({ UsagerService.class, UsagerRepository.class })
#Tag(TestCase.INTEGRATION)
public class UsagerControllerIT {
#Autowired
private WebTestClient wtc;
#Test
public void getUsager_returnUsager() {
ResponseSpec rs = wtc.get().uri("/usager").exchange();
rs.expectStatus().isOk();
rs.expectHeader().contentType(MediaType.APPLICATION_JSON);
rs.expectBody(Usager.class).isEqualTo(new Usager());
}
}
I get the following exception:
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.dsi.bibliosys.biblioback.repository.UsagerRepository]: Specified class is an interface
I don't understand why Spring can't inject the repository.
Does somebody have an idea ?
I tried another approach using #SpringBootTest. Here is my new test class :
#ExtendWith(SpringExtension.class)
#SpringBootTest
#Tag(TestCase.INTEGRATION)
public class UsagerController02IT {
#Autowired
private UsagerController usagerController;
#Test
public void getUsager_returnUsager() {
WebTestClient wtc = WebTestClient.bindToController(usagerController).build();
ResponseSpec rs = wtc.get().uri("/usager").exchange();
rs.expectStatus().isOk();
rs.expectHeader().contentType(MediaType.APPLICATION_JSON);
rs.expectBody(Usager.class).isEqualTo(new Usager());
}
}
I get this exception:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.dsi.bibliosys.biblioback.controller.UsagerController': Unsatisfied dependency expressed through field 'usagerService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.dsi.bibliosys.biblioback.service.entity.UsagerService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
I don't understand why UserService is not available in the application context.
Thanks for your help.
This looks very similar to this. I'd suggest investigating your test configuration and adding it if appropriate.
A quote from Spring on #WebFluxTest
Using this annotation will disable full auto-configuration and instead apply only configuration relevant to WebFlux tests (i.e. #Controller, #ControllerAdvice, #JsonComponent, Converter/GenericConverter, and WebFluxConfigurer beans but not #Component, #Service or #Repository beans).
I am using a mock repository for my application.
Here is snippet how service looks:
#Service
public class WeatherStationService {
#Autowired
private WeatherStationRepositoryMock weatherRepository;
Here is repository code:
#Repository
public class WeatherStationRepositoryMock {
#Getter
private List<WeatherStation> stations = new ArrayList<>(
Arrays.asList(
new WeatherStation("huston", "Huston station", RandomGenerator.getRandomGeoInformation()),
new WeatherStation("colorado", "Colorado station", RandomGenerator.getRandomGeoInformation())
)
);
It works fine when I am executing main() with #SpringBootApplication.
However, when I want to run test class:
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = MockConfig.class)
#DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
public class WeatherStationServiceTest {
#Autowired
#Real
private WeatherStationService weatherService;
It fails with the following stacktrace:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'edu.lelyak.repository.WeatherStationRepositoryMock' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
Here is MockConfig content:
#Configuration
public class MockConfig {
//**************************** REAL BEANS ******************************
#Bean
#Real
public WeatherStationService weatherServiceReal() {
return new WeatherStationService();
}
Real is marker annotation for real instances:
#Retention(RUNTIME)
#Qualifier
public #interface Real {
}
I can fix it with next initialization at service:
#Service
public class WeatherStationService {
private WeatherStationRepositoryMock weatherRepository = new WeatherStationRepositoryMock();
It works fine.
Why does this happen?
How to fix autowiring for my custom repository class?
#SpringBootApplication implicitly defines #ComponentScan, which scans all subpackages for beans.
When you run a test using MockConfig's, it doesn't scan for beans.
Solution - use #ComponentScan OR define beans in MockConfig
(1) Using #ComponentScan:
#Configuration
#ComponentScan //Make sure MockConfig is below all beans to discover
public class MockConfig {
#Bean
#Real
public WeatherStationService weatherServiceReal() {
return new WeatherStationService();
}
}
(2) or define required beans:
#Configuration
public class MockConfig {
#Bean
#Real
public WeatherStationService weatherServiceReal() {
return new WeatherStationService();
}
#Bean
public WeatherStationRepositoryMock weatherStationRepository() {
return new WeatherStationRepositoryMock()
}
}
I Create the bean by configuration with out name
#Configuration
#ConfigurationProperties(prefix = "mysql")
public class DbConfiguration extends BaseDbConfiguration {
#Bean//(name = "fix")
#Override
public DbClient createClient() {
return super.createClient();
}
}
usage:
#Autowired
private DbClient dbClient;
when I running application it can't start up
And throw NoSuchBeanDefinitionException:
No qualifying bean of type [DbClient] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.
Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
But I fix it by add name, why??
#Bean(name = "fix")
I also add a test such like this:
public class TestCreate {
#NotNull
private int test;
public Test createTest() {
return new Test(this.test);
}
}
it configuration like this:
#Configuration
#ConfigurationProperties(prefix = "test")
public class TestConfiguration extends TestCreate {
#Override
#Bean
public Test createTest() {
return super.createTest();
}
}
And autowired like this:
#Autowired
private Test test;
However, this test may work well
It also create Bean without name and Autowired with out Qualifier
Please Tell me why....thanks
Sorry.
I have found the results:
Overriding bean definition for bean 'createClient': replacing ...
So Spring-Boot will create Bean by FunctionName rather than returning ObjectName.
Im new to Spring, last couple of days I've been learning about it. Now Im trying to do something with it. It seems to me that with spring boot everything has changed.
There is no applicationContext file, I should use #Bean. Ok. In in tutorials the code is working, for me it fails. What did I miss?
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
the controller:
#RestController
public class GreetingController {
private final Test test;
#Autowired
public GreetingController(Test test){
this.test = test;
}
#RequestMapping("/greeting")
public String greeting(#RequestParam(value = "name", defaultValue = "World") String name) {
return "greeting" + test.getTest();
}
}
class Test {
public String getTest() {
return "tetst";
}
}
error:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [hello.Test] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1301)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1047)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:942)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:813)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741)
... 18 more
I assume that bean has to be defined... But in tutorials there is no defenicion of bean.. Or I didnt see it.
Test class is not recognized as a Spring component. Therefore, you cannot inject it in your GreetingController. In order to inject Test object in that controller, annotate Test class with like #Component annotation (or with some other annotation that indicates that your class can be auto scanned).
Missed the full error. You need #Component on Test.