How to inject mocks with Springboot? - java

I want to inject a mock into my Springboot application. I get this error:
Error creating bean with name 'ca.company.TestA': Unsatisfied dependency expressed through field 'a'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'ca.company.hello.A' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
I'm stuck and don't understand how to process. I Defined A to be autowired. What's the problem?
Here is my test file:
#RunWith(SpringJUnit4ClassRunner.class)
public class TestA {
#Autowired
private A a;
private B Bmock;
#Before
public void before() {
Bmock = Mockito.mock(B.class);
ReflectionTestUtils.setField(a, "b", Bmock);
}
#Test
public void testSpeak() {
when(Bmock.writeToScreen()).thenReturn("Everything will be alright");
assert(true);
}
}
here is the config file:
#Configuration
public class Config {
#Bean
public B b() {
return new B();
}
// The error persists whether I define this bean or not
#Bean
public A a() {
return new A();
}
}
And here is the class in question:
#Component
public class A {
#Autowired
private B b;
public void speak() {
System.out.println(b.writeToScreen());
}
}
And finally here is my file structure:
What am I doing wrong, I don't get it.

Your configuration class is not processed by Spring. The simplest way to achieve that is to put #ContextConfiguration(classes = Config.class) in your test class.

Related

Spring #Bean Inject Enum

In my Config I define two beans of the same class that differ in the value of an enum:
#Bean
public MyClass myClassNew() {
return new MyClass(Source.NEW);
}
#Bean
public MyClass myClassOld() {
return new MyClass(Source.OLD);
}
The Class looks like this:
#Component
#RequiredArgsConstructor
public class MyClass {
private final Source source; // Source is an enum
}
When I autowire a bean in a test:
public class MyClassTest {
#Autowired
private MyClass myClassNew;
}
Spring gives me the following error:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type '...AClass$Source' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
This is totally weird. Why does Spring trying to find a bean of an enum?

NoSuchBeanException, even when Bean is defined

I have 2 classes.
Target.java: Class to be tested
Helper.java: Helper class
#Component
public class Helper {
public void helperMethod() {
// some code
}
}
#Service
public class Target {
private final Helper helper;
public Target(Helper helper) {
this.helper = helper;
}
public void someMethod() {
helper.helperMethod();
}
}
I am testing someMethod() method of Target class. But when running the test case it gives following error:
Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.abc.def.Helper' available: expected at least 1 bean which qualifies as autowire candidate.
Other answers that I have seen for similar question were because of not writing #Component, but I have done that too.
You have provided the correct annotations for the 2 classes in order to ensure that spring treats them as a component and manage their life cycles. Now, if you want to use these beans in any part of the application you would need to declare the dependency for that, the easiest way is as below by using the #Autowired annotation, there are mulitple ways to define dependency and you can choose the best options for your use case accordingly:
#Service
public class Target {
#Autowired
private final Helper helper;
public Target(Helper helper) {
this.helper = helper;
}
public void someMethod() {
helper.helperMethod();
}
}
Not sure if I understood you correctly, but I also had similiar issue when writing tests for my application using JUnit. My workaround was to put in my TestClass configuration where I define beans which i need for testing. E.g.
#RunWith(SpringRunner.class)
public class TestSomeService {
#TestConfiguration
static class TestSomeServiceConfiguration {
#Bean
public Helper helper() { return new Helper(); }
#Bean
public Target targer() {
return new Target(
helper()
);
}
}
#Autowired
private Target targetUnderTest;
#Test
public void testTarget() {
}
}

Unresolved dependency in UnitTesting Spring Boot

I getting the following error when trying to write a unit test for CircuitBreaker code example.
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name
'com.foosball.team.Service.TeamServiceUnitTest': Unsatisfied
dependency expressed through field 'registry'; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type
'io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry'
available: expected at least 1 bean which qualifies as autowire
candidate. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
TeamService:
#Service
public class TeamService {
#Autowired
private ITeamRepository teamRepository;
#Autowired
private PlayerClient playerClient;
Logger logger = LoggerFactory.getLogger(TeamService.class);
.
.
.
TeamServiceUnitTest:
#SpringBootTest(classes = {
TeamService.class
})
#RunWith(SpringRunner.class)
#DirtiesContext
public class TeamServiceUnitTest extends AbstractCircuitBreakerTest {
#MockBean
private ITeamRepository teamRepository;
#MockBean
private PlayerClient playerClient;
#Autowired
private TeamService service;
private TeamEntity teamEntity;
private Logger logger = LoggerFactory.getLogger(TeamServiceUnitTest.class);
#Before
public void setUp(){
teamEntity = new TeamEntity();
teamEntity.setId(1L);
teamEntity.setPlayerOne("One");
teamEntity.setPlayerTwo("Two");
teamEntity.setPlayerThree("Three");
teamEntity.setPlayerFour("Four");
}
#Test
#DisplayName("when Player Client Fails 11 Times Then CircuitBreaker Should Be In OPEN State")
public void whenPlayerClientFailsElevenTimesThenCircuitBreakerShouldBeInOPENState(){
//Given
when(teamRepository.findAll()).thenReturn(new ArrayList<>());
when(playerClient.get(Mockito.anyString())).thenThrow(new RuntimeException());
//When
for(int i=0; i<11; i++){
try {
service.addTeam(teamEntity);
} catch (Exception ignore) {
logger.info(ignore.getClass().getName());
}
}
//Then
checkHealthStatus(BACKEND_B, CircuitBreaker.State.OPEN);
}
}
Ref Class:
public class AbstractCircuitBreakerTest {
protected static final String BACKEND_A = "backendA";
protected static final String BACKEND_B = "playerClientCircuitBreaker";
#Autowired
protected CircuitBreakerRegistry registry;
#Before
public void setup(){
transitionToClosedState(BACKEND_A);
transitionToClosedState(BACKEND_B);
}
protected void checkHealthStatus(String circuitBreakerName, CircuitBreaker.State state) {
CircuitBreaker circuitBreaker = registry.circuitBreaker(circuitBreakerName);
assertThat(circuitBreaker.getState()).isEqualTo(state);
}
protected void transitionToOpenState(String circuitBreakerName) {
CircuitBreaker circuitBreaker = registry.circuitBreaker(circuitBreakerName);
if(!circuitBreaker.getState().equals(CircuitBreaker.State.OPEN)){
circuitBreaker.transitionToOpenState();
}
}
protected void transitionToClosedState(String circuitBreakerName) {
CircuitBreaker circuitBreaker = registry.circuitBreaker(circuitBreakerName);
if(!circuitBreaker.getState().equals(CircuitBreaker.State.CLOSED)){
circuitBreaker.transitionToClosedState();
}
}
}
Ref Project: https://github.com/resilience4j/resilience4j-spring-boot2-demo
Proposed Soln Discussion: https://github.com/resilience4j/resilience4j-spring-boot2-demo/issues/33
Proposed Soln Project: https://github.com/shah-smit/resilience4j-spring-boot2-demo-maven
Looks like CircuitBreakerRegistry you're trying to autowire in you test is a factory class, not a bean. Instead of
#Autowired
protected CircuitBreakerRegistry registry;
Try:
protected CircuitBreakerRegistry registry = CircuitBreakerRegistry.ofDefaults()
Here's an answer about not working tests.
Few things here:
1. Using CircuitBreakerRegistry.ofDefaults() creates new instance of object each time so this way the CircuitBreakerRegistry objects you're using in AbstractCircuitBreakerTest and HomeService are different instances. You should probably go back to #Autowired annotation but first you need to define bean of CircuitBreakerRegistry like this:
public class CircuitBreakerConfiguration {
#Bean
public CircuitBreakerRegistry circuitBreakerRegistry() {
return CircuitBreakerRegistry.ofDefaults();
}
}
You're using #RunWith(SpringRunner.class) but it's just Junit annotation and it does not initialize Spring Context in your test. You're autowiring a bean in your test so you need Spring Context. For this add also #SpringBootTest annotation.
You're expecting the registry BACKEND_A state to change to OPEN after 11 calls of service.getGreeting() method but I cannot see any usage of transitionToOpenState method.

#Autowired #Bean from other class

#Configuration
public class Class1 {
#Bean
public JavaMailSenderImpl mailSender() {
....
}
}
#Component
public class Class2 {
#Autowired
JavaMailSenderImpl mailSender;
And I still get:
No qualifying bean of type [org.springframework.mail.javamail.JavaMailSenderImpl] 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)}
Could not autowire field: org.springframework.mail.javamail.JavaMailSenderImpl (path_of_where_autowiring); nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.mail.javamail.JavaMailSenderImpl] 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)}
The Class1 bean location is in Package1 and the Class2 location is in Package2.
Why my bean is not found? Help
(Also tried this link but didn't helped me)
EDIT
public static void main(String[] args) throws URISyntaxException, IOException {
ConfigurableApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);
Implclass nsi = applicationContext.getBean(Implclass.class);
nsi.the_method_here();
}
#Component
public class Implclass implements Implinterface {
#Autowired
JavaMailSenderImpl mailSender;
#Override
public void the_method_here(){
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom(sender);
message.setTo(receiver);
message.setSubject(subject);
message.setText(content);
mailSenderService.send(message);
}
}
#Configuration
#ComponentScan
public class SpringConfiguration {
#Bean
public PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
propertyPlaceholderConfigurer.setLocations(new ClassPathResource("some_property.file"));
propertyPlaceholderConfigurer.setIgnoreUnresolvablePlaceholders(true);
return propertyPlaceholderConfigurer;
}
}
EDIT (TREE)
x - src/main/java
x -- package_1
x - Class1
x -- package_2
x - Class2 (ImplClass)
Use #ComponentScan({"Package1", "Package2"})
Can you please try with using different names.
Reference Link : https://dzone.com/articles/playing-sround-with-spring-bean-configuration
#Configuration
public class Class1 {
#Bean
public JavaMailSenderImpl mailSenderWithInjection() {
....
}
}
#Component
public class Class2 {
#Autowired
JavaMailSenderImpl mailSender;
}
you can use#ComponentScan
or
ctx = new AnnotationConfigApplicationContext();
ctx.register(Config.class); // config
ctx.refresh();
// and try
Implclass nsi = ctx.getBean(Implclass.class);
AnnotationConfigApplicationContext can take multiple configuration classes in the constructor. Can you try passing all the configuration files in the constructor as Step-1. Then it can be further debugged to better the solution.
AnnotationConfigApplicationContext(Class<?>... annotatedClasses)
e.g.
ConfigurableApplicationContext applicationContext = new AnnotationConfigApplicationContext(Class1.class, Class2.class, SpringConfiguration.class);
Also, where is your ImplClass, posting a tree structure would have been very helpful.

Autowiring fails in Junit testing and spring #configuration

I have two #Configuration classes. I need a bean from one configuration class to another. I have autowired the configuration 1 into 2. All works fine. When executing the unit testing, am getting the below exception.
setUpContext(com.trafigura.titan.framework.services.messaging.loader.SpringLoadTest)
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.xxx.MessagingServicesConfig': Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.xxx.EMSJMSConfig com.xxx.MessagingServicesConfig.emsJmsConfig;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type[com.xxx.EMSJMSConfig] 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)}
Is there anything I need to do additionally to make this working?
Below is the setup for testing.
#Configuration
#Import({MessagingServicesConfig.class,...,EMSJMSConfig.class
})
public class MessagingConfig {}
#Profile("EMS-MESSAGING")
#Configuration
public class EMSJMSConfig {
#Bean
public javax.jms.ConnectionFactory jmsSubscriberConnectionFactory() throws JMSException {
SingleConnectionFactory singleConnectionFactory = new SingleConnectionFactory(tibjmsConnectionFactory());
return singleConnectionFactory;
}
}
#Configuration
public class MessagingServicesConfig {
#Autowired
private EMSJMSConfig emsJmsConfig;
#Bean(destroyMethod = "shutdown")
public MessagingService messagingService() throws JMSException {
...
ConnectionFactory cf=emsJmsConfig.jmsSubscriberConnectionFactory(); // Getting NPE at this line.
}
}
and finally the test class,
public class MessagingServicesConfigTest {
private MessagingServicesConfig config;
private EMSJMSConfig emsJmsConfig;
#BeforeMethod
public void setUp() throws Exception {
config = new MessagingServicesConfig();
... //what needs to be done here to have the EMSJMSConfig
}
#Test
public void testBuildsCorrectService() throws JMSException {
MessagingService service = config.messagingService();
...
}
}
By calling new you're creating object yourself, Spring doesn't know anything about it.
Moreover, you should have a test configuration which will be aware of your beans.
Use an appropriate Runner to load SpringContext.
#ContextConfiguration(classes = TestConfig.class)
#RunWith(SpringRunner.class)
class Tests {
#Autowired // if needed
private MessagingServicesConfig config;
}
While in TestConfig you can create beans or import configuration from the Application:
#Configuration
#Import({MessagingServicesConfig.class})
public class TestConfig {}
#Configuration
#Import({EMSJMSConfig.class})
public class MessagingServicesConfig {}
Or you can refer to your config classes directly:
#ContextConfiguration(classes = {MessagingServicesConfig.class, EMSJMSConfig.class})

Categories