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() {
}
}
Related
My Problem: I have created a Singleton Bean of my model Manager. Trying to Autowire it in my Controller, however, results in a nullpointer. In my configuration, however, the Autowiring of the same Bean works just fine.
I should note at this point that this is not the first singleton Bean I have made in this project; and as far as I can tell, I have made it in the same vein as all the others; which all Autowire correctly. That's the main reason why I'm stumped right now.
The Code:
The Main App is under the 'project' package, so all other packages are sub-packages of that one.
I opted to omit the imports for brevity, but everything is imported as it should be.
Config
package project.config
#Configuration
public class BootstrapConfig {
#Bean
#Scope("singleton")
public ThingManager thingManager() {
return new thingManager();
}
#Autowired
private ThingManager manager;
#PostConstruct
public void initialize() {
manager.setup() //This works fine.
}
}
Manager
package project.model
public class ThingManager {
private HashMap<String, Thing> things;
public ThingManager() {
things = new HashMap<String, Thing>();
}
public void setup() {
//Do setup Things
}
public Thing getThing(String input) {
return things.get(input);
}
}
Controller
package project.controller
#RestController
#RequestMapping("/api/things")
public class ThingController {
#Autowired
ThingManager manager; //This is null
private Thing thing;
public ThingController() {
this.thing = manager.getThing("test"); //This then throws NullPointer.
}
#GetMapping("/")
public ResponseEntity<Thing> showThing() {
return ResponseEntity.ok(thing);
}
}
What I have tried:
I have tried marking ThingManager as #Component #Scope(value = "singleton")instead of setting up the Bean manually (so I removed the #Bean code-block in the configuration); the result is the same; Configuration can Autowire it perfectly fine, but Controller cannot.
I have looked at the myriad of posts about this topic already on here, but most seem to be about someone having forgotten to mark the class they Autowire in as a component or similar. Maybe I overlooked a similarity to my problem; it's hard to tell.
Spring can autowire fields only after the object is created (the constructor is called), so you're accessing the manager in the constructor of ThingControler while it's not yet injected. The easiest way to use manager in the constructor would be to add it as a constructor parameter instead of autowiring (Spring will use available bean for the parameter):
// ...
public class ThingController {
private final Thing thing;
public ThingController(ThingManager manager) {
this.thing = manager.getThing("test");
}
// ...
}
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.
I am trying to add a simple String to my Spring Application Context, and then autowire this to a different existing bean (A) within the application context. I know this is not the usual way to go, yet I need to add many beans programmatically, which would otherwise make my xml configuration huge.
public class MyPostProcessor implements BeanFactoryPostProcessor, Ordered {
#Override
public int getOrder() {
return 0;
}
#Override
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory) throws BeansException {
beanFactory.registerSingleton("myString", "this is the String");
A a = beanFactory.getBean(A.class);
beanFactory.autowireBean(a);
}
}
public class A {
#Autowired
public transient String message;
}
When running this, the property message of the instance of A is null. What am I missing?
EDIT: this is my application context:
#Configuration
class TestConfig {
#Bean
public A a() {
return new A();
}
#Bean
public MyPostProcessor postProcessor() {
return new MyPostProcessor();
}
}
And this is my test:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = TestConfig.class)
public class MyTest {
#Autowired
private transient A a;
#Test
public void test() throws Exception {
System.err.println("Running");
System.err.println("This is the autowired String: " + a.message);
Thread.sleep(1000);
}
}
Thanks
You should not instantiate beans from BeanFactoryPostprocessors.
From BeanFactoryPostProcessor JavaDoc:
A BeanFactoryPostProcessor may interact with and modify bean
definitions, but never bean instances. Doing so may cause premature
bean instantiation, violating the container and causing unintended
side-effects.
In your case, the A bean is instantiated before BeanPostProcessors and therefore not autowired.
Remove the lines:
A a = beanFactory.getBean(A.class);
beanFactory.autowireBean(a);
And will work.
Try using the #Qualifier to specific which bean you want to Auto wire.
public class A {
#Autowired
#Qualifier("myString")
public transient String message;
}
I want configure a component test using spring-test configuration inner class (#Configuration). Tested components has some services which I'd like to mock for the test. These services are classes (no interface used) and have spring annotations (#Autowired) in them. Mockito can easily mock them, however, I found no way of disabling spring autowiring.
Example how I can easily reproduce:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = SomeTest.Beans.class)
public class SomeTest {
// configured in component-config.xml, using ThirdPartyService
#Autowired
private TestedBean entryPoint;
#Test
public void test() {
}
#Configuration
#ImportResource("/spring/component-config.xml")
static class Beans {
#Bean
ThirdPartyService createThirdPartyService() {
return mock(ThirdPartyService.class);
}
}
}
public class ThirdPartyService {
#Autowired
Foo bar;
}
public class TestedBean {
#Autowired
private ThirdPartyService service;
}
In this example "TestBean" represents the service to be mocked. I would NOT like "bar" to be injected by spring! #Bean(autowire = NO) does not help (in fact, that's the default value).
(Please save me from "use interfaces!" comments - the mocked service can be 3rd party which I can't do anything with.)
UPDATE
Springockito partially solves the problem, as long as you don't have to have anything else to configure (so you can't use configuration class with Springockito - it does not support it), but use mocks only.
Still looking for pure spring solution, if there's any...
Here is my solution to your problem:
import static org.mockito.Mockito.mockingDetails;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class MockitoSkipAutowireConfiguration {
#Bean MockBeanFactory mockBeanFactory() {
return new MockBeanFactory();
}
private static class MockBeanFactory extends InstantiationAwareBeanPostProcessorAdapter {
#Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return !mockingDetails(bean).isMock();
}
}
}
and then just
#Import(MockitoSkipAutowireConfiguration.class)
in your test #Configuration and you are all set
I solved it by creating FactoryBean for my bean instead of just mocking bean. At this way Spring don't try to autowire fields.
Factory bean helping class:
public class MockitoFactoryBean<T> implements FactoryBean<T> {
private final Class<T> clazz;
public MockitoFactoryBean(Class<T> clazz) {
this.clazz = clazz;
}
#Override public T getObject() throws Exception {
return mock(clazz);
}
#Override public Class<T> getObjectType() {
return clazz;
}
#Override public boolean isSingleton() {
return true;
}
}
Actual test context part:
#Configuration
public class TestContext {
#Bean
public FactoryBean<MockingService> mockingService() {
return new MockitoFactoryBean<>(MockingService.class);
}
}
Check Spring profiles. You don't need to disable auto wiring, you need to inject different beans for different configuration.
You could add the mocked service manually to the spring application context via org.springframework.beans.factory.config.SingletonBeanRegistry#registerSingleton. This way the mock is not post-processed by spring and spring does not attempt to autowire the mock. The mock itself will be injected into your tested bean.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = SomeTest.Beans.class)
public class SomeTest {
// configured in component-config.xml, using ThirdPartyService
#Autowired
private TestedBean entryPoint;
#Autowired
private ThirdPartyService thirdPartyServiceMock;
#Test
public void test() {
}
#Configuration
static class Beans {
#Autowired
private GenericApplicationContext ctx;
#Bean
TestedBean testedBean() {
ctx.getBeanFactory().registerSingleton("thirdPartyService", mock(ThirdPartyService.class));
return new TestedBean();
}
}
public static class ThirdPartyService {
#Autowired
Object bar;
}
public static class TestedBean {
#Autowired
private ThirdPartyService service;
}
}
I am in quite the same situation.
What I found that if you do not set the context loader by #ContextConfiguration annotation on your test class, the default context loader will be used, which derived from AbstractGenericContextLoader. I had a look at its source and turned out it registers all the bean post processors which are responsible for reading annotations such #Autowired. In other words, annotation config is enabled by default.
So the main problem is that there are two configurations which are in conflict: in the java config we said that autowiring is not needed, while the autowired annotation tells the opposite. The real question is how to disable the annotation processing in order to eliminate the undesired configuration.
As far as I know there is no such spring implementation of ContextLoader which would not be derived from AbstractGenericContextLoader so I guess the only we can do is to write our own. It would be something like this:
public static class SimpleContextLoader implements ContextLoader {
#Override
public String[] processLocations(Class<?> type, String... locations) {
return strings;
}
#Override
public ApplicationContext loadContext(String... locations) throws Exception {
// in case of xml configuration
return new ClassPathXmlApplicationContext(strings);
// in case of java configuration (but its name is quite misleading)
// return new AnnotationConfigApplicationContext(TestConfig.class);
}
}
Of course it would be worth to spend more time to find out how to implement ContextLoader properly.
Cheers,
Robert
There are so many ways of doing this, I'm pretty sure that this answer will be incomplete, but here are a few options...
As currently seems to be recommended practice, use constructor injection for your services rather than autowiring the fields directly. This makes testing like this so much easier.
public class SomeTest {
#Mock
private ThirdPartyService mockedBean;
#Before
public void init() {
initMocks(this);
}
#Test
public void test() {
BeanUnderTest bean = new BeanUnderTest(mockedBean);
// ...
}
}
public class BeanUnderTest{
private ThirdPartyService service;
#Autowired
public BeanUnderTest(ThirdPartyService ThirdPartyService) {
this.thirdPartyService = thirdPartyService;
}
}
By doing that, you can also mix up autowired and mocked services by autowiring into the test itself and then constructing the beans under test with the most useful mix of autowired and mocked beans.
A reasonable alternative is to use Spring profiles to define stub services. This is particularly useful when wish to use the same stubbed features in multiple tests:
#Service
#Primary
#Profile("test")
public class MyServiceStub implements MyService {
// ...
}
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = SomeTest.Beans.class)
#ActiveProfiles({"test"})
public class SomeTest {
// ...
}
By using the #Primary annotation, it ensures that this stub bean will be used instead of any other bean implementing the MyService interface. I tend to use this approach for things like email services, where by changing profile, I'm able to switch between a real mail server and Wiser.
Here's the problem: I have a rather complex class B with lots of #Inject defined in it (among them a class C). An instance of this class is injected into another class A, which I want to be tested.
The idea is that I want to inject a mock of class B into A - and I want it to be injected by spring to have the init-method be executed after the instance is created (so no #InjectMock here to have an alternative injection).
Here's an example that is boiled down to three classes Bla, Blub and Blublub. What I want to do is have a mock of Blub and inject this instance into BlubBlub - and I want to ignore the existence of Bla.
*Edited*
The main point is that I want a context to consists of a mock of class Blub and an instance of class BlubBlub.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = MockInjectionTest.TestApp.class)
public class MockInjectionTest {
#Inject
public Blub blub;
#Inject
public BlubBlub blubblub;
#Configuration
public static class TestApp {
#Bean
Blub getBlub() {
return mock(Blub.class);
}
#Bean
BlubBlub getBlubBlub() {
return new BlubBlub();
}
}
#Test
public void testBlub() {
Assert.assertNotNull(blub);
}
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
// the classes
public static class Bla {
}
public static class Blub {
#Inject
public Bla bla;
}
private static class BlubBlub {
#Inject
public Blub blub;
}
}
Problem: when I define a mock of Blub either by using #Mock or by calling mock(Blub) explicitly in a #Bean method I get the following error when the ApplicationContext is instantiated (no matter whether I use xml-config or annotation-based bean definitions).
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating
bean with name 'getBlub': Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException:
Could not autowire field: public Bla Blub.bla;
so apparently Spring still want to instantiate the original class instead of just taking my provided instance. This seams to be necessary to create the context (if I create the context by hand and pull the bean with ctx.getBean() it dumps already in the context construction).
Coming from Guice I would simple bind my mocked instance into the module and everything would be fine.
Help is much appreciated - sounds like a standard problem but I couldn't find a simple solution.
thanks and regards, fricke
Change your configuration to
#Configuration
public static class TestApp {
#Bean
Blub getBlub() {
return mock(Blub.class);
}
#Bean
BlubBlub getBlubBlub() {
return new BlubBlub();
}
#Bean
Bla getBla() {
return mock(Bla.class)
}
}
What Spring is complaining about is the fact that no Bla implementation is present in the application context and there for no injection can be performed
You can return a null bean like this :
#Configuration
public static class TestApp {
#Bean
Blub getBlub() {
return mock(Blub.class);
}
#Bean
Bla getBla() {
return null;
}
#Bean
BlubBlub getBlubBlub() {
return new BlubBlub();
}
}
This will avoid injection on Bla instances, since there is none.
This is not ideal when you have many #Injects, but this works.
Another solution wich is not ideal also, is to have your bean implement an interface, and mock the interface instead of the implementation class.
I tried springockito, this would work for your case, but in one of my test case wich was about testing a custom BeanDefinitionRegistryPostProcessor, it was messing to much the normal spring behavior in think.