So I have a class called ClientFactory that I import into my project using a jar. It looks like this:
#Component
public class ClientFactory {
#Autowired
private Client client;
public ClientFactory() {
}
public Client get() {
return this.client;
}
}
and my class that uses this looks like:
#SpringBootApplication(scanBasePackages = {"path.to.client.*"})
#EnableAutoConfiguration
public class ProjectClient {
#Autowired
public ClientFactory clientFactory;
public ProjectClient() {}
public String getSomething(String something){
Client client = (Client) clientFactory.get();
return "x";
}
}
And I call this piece of code from my test class:
#SpringBootTest
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
#Disabled
#TestPropertySource(properties = { //
"some.property=value", //
})
public class SomeTests {
#Autowired
ProjectClient p;
#Test
public void sampleTest() throws Exception {
p.getSomething("sample");
}
}
and I get the following error:
Field clientFactory in ProjectClient required a bean of type 'ClientFactory' that could not be found.
Action:
Consider defining a bean of type 'ClientFactory' in your configuration.
I've tried all combinations of Entity, Component and Package scans but nothing seems to be working. The application simply cannot find that bean, I've googled high and low and can't seem to find a way to get this working - I'm new to Spring boot - please help :(
I believe this class isn't compiling properly.
#Component
public class ClientFactory {
#Autowired
private Client client;
public Factory() {
}
public Client get() {
return this.client;
}
}
While Class name is ClientFactory the constructor been defined as Factory, which isn't possible for compiler to compile it.
Would you please change Factory to ClientFactory (OR Remove default constructor If you don't have specific use) and try again
Create clientfactory with bean annotation since you are referring clientFactory by importing from jar
#Bean
public Clientfactory clientfactory () {
return new Clientfactory ();
}
It took me too long but I figured it out. I made a change to ProjectClient as follows:
#Service
#ComponentScan(basePackages = {"path.to.*"})
public class ProjectClient {
I'm guessing my path to client was incorrect or undetectable (I used the same path for importing that class).
Looks like you have forgotten to add #RunWith(SpringRunner.class) on your test class.
Related
I have call method which is defined in NoteService interface, the implementation of this method is in NoteImpl class. I am trying to access this method from Refresh class, but I am getting this error
Parameter 3 of constructor in com.new.macro.rest.Refresh required a bean of type 'com.new.macro.unity.processorService' that could not be found.
Action:Consider defining a bean of type 'com.new.macro.unity.NoteService' in your configuration.
I need help resolving this error.
Here is my Refresh class from where I try to access call method from NoteImpl class
package com.new.macro.rest;
#Component
public class Refresh implements BaseService {
private final NoteService<Inbuild> iNoteService;
public Refresh(final NoteService iNoteService) {
this.iNoteService = iNoteService;
}
#PUT
public String firstRefresh() {
iNoteService.call(Types);
return RefreshStatus.STARTED.toJsonResponse();
}
Here is NoteImpl class with call method functionality
#Configuration
public abstract class NoteImpl implements NoteService{
private static final Logger LOGGER = LogManager.getLogger(NoteImpl.class);
private final RestTemplate restTemplate;
private final String Url;
public NoteImpl( RestTemplate restTemplate,#Value("${url}") String Url){
this.restTemplate = restTemplate;
this.Url = Url;
}
public void call(Set<Inbuild> Types, String Url) {
Set<String> results = new HashSet<>();
\\ Remaining functionality
}
}
Here is the interface
package com.new.macro.unity;
import java.util.Set;
public interface NoteService<T> {
void call(Set<? extends T> Types);
}
Add #Autowired annotation on head of constructor:
#Autowired
public Refresh(final NoteService iNoteService) {
this.iNoteService = iNoteService;
}
Then you will get a bean from NoteService.
Assuming all these classes are classpath scanned:
- NoteImpl shouldn't be abstract
- NoteImpl should be annotated as #Component instead of #Configuration. Configuration classes are the ones that create beans
To fix this, don't keep NoteImpl as abstract class - abstract classes can't be instantiated. That should resolve the problem. Though #Configuration will work(as it's meta annotated with #Component), #Service makes sense here.
Also, you don't need #Autowired at constructor injection - that is optional. (So the other answer won't solve the problem)
I have a service which needs to create Agents on the runtime. Agents inherit from a base Agent class. I would like to use the Autowired ability of spring instead of doing my own dependency injections.
But I am running into this issue, even though I am marking the component as scope=prototype, and even #Lazy to prevent anything from happening at compile-time.
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.my.project.AgentType1 required a bean of type 'com.my.project.POJO' that could not be found.
This is the service that tries to create the agents:
#Service
public class ProjectMain {
#Autowired
ApplicationContext context;
List<IAgent> agents = new ArrayList<>();
void SetupAgents(List<POJO> agentPojos) {
for(POJO agentPojo: agentPojos) {
IAgent agent = AgentFactory.CreateAgent(agentPojo, context);
agents.add(agent);
}
}
}
This is the factory class, not marked as #Component etc. It uses the context passed to it to create the child class beans. It tries to pass the constructor argument via the getBean method.
public class AgentFactory {
public static IAgent CreateAgent(POJO agentPojo, ApplicationContext context) {
if (agentPojo.type.equals("AgentType1")) {
return context.getBean(AgentType1.class, agentPojo);
} else {
return context.getBean(AgentType2.class, agentPojo);
}
}
}
This is a custom annotation which I found is needed for inheritance scenarios.
#Target({ ElementType.TYPE })
#Retention(RetentionPolicy.RUNTIME)
#Component
#Inherited
#Lazy
#Scope("prototype")
public #interface AgentAnnotation {}
These are the base and child agent classes, which need a custom data structure called POJO to work.
#AgentAnnotation
public class BaseAgent implements IAgent {
#Autowired
Environment env;
public BaseAgent(POJO agentPojo, String someotherdata) {
}
}
public class AgentType1 extends BaseAgent {
public AgentType1(POJO agentPojo) {
super(agentPojo, "mydata1");
...
}
}
public class AgentType2 extends BaseAgent {
public AgentType2(POJO agentPojo) {
super(agentPojo, "mydata2");
...
}
}
This is the starter app.
#ComponentScan(basePackages = "com.my.project", includeFilters = #ComponentScan.Filter(AgentAnnotation.class))
#EnableScheduling
#SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
I also tried the configuration approach:
#Configuration
public class BaseAgentConfig {
#Bean
#Scope("prototype")
public AgentType1 agentType1(POJO agentPojo) {
return new AgentType1(agentPojo);
}
#Bean
#Scope("prototype")
public AgentType2 agentType2(POJO agentPojo) {
return new AgentType2(agentPojo);
}
}
In this case, I removed the #AgentAnnotation from the baseAgent class as we are now instantiating through this config. Also removed the ComponentScan line from the main App.
This time around, the #Autowired doesn't work. All Autowired references in the baseAgent class are null.
Please advise on the best approach to solve this error. Thanks.
Found the issue and solution.
Basically, I was expecting child classes to inherit #Component and #Scope, which it doesn't.
So essentially, I need to annotate each child class with #Component and #Scope("prototype").
The other problem was that I was expecting Autowired items in the constructor, which was too early. Adding a #PostConstruct addressed that issue.
So I ended up deleting the custom annotation and the configuration class and making the changes I just described.
This is the setup of the test class:
#RunWith(PowerMockRunner.class)
#PowerMockIgnore("javax.management.*")
#PowerMockRunnerDelegate(SpringRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = ServiceApplication.class)
#PrepareForTest({ MyClass.class })
public class ControllerTest {
#Autowired
public TestRestTemplate restTemplate;
public static MyClass myClass = Mockito.mock(MyClass.class);
#BeforeClass
public static void beforeClassSetup() throws Exception {
PowerMockito.mockStatic(MyClass.class);
BDDMockito.given(MyClass.getInstance(Mockito.anyString())).willReturn(myClass);
BDDMockito.given(myClass.foo()).willReturn("BAR");
// ...
}
.
.
.
// test cases
In configuration class of this project, for load some beans, I use this static call for generate the instance.
#Configuration
#ComponentScan(basePackages = { "package.from.another.project.in.production" })
public class Beans {
#Bean
public MyClass myClass() {
return MyClass.getInstance(K.FOO);
}
}
This is my controller that uses the bean, as well as the static call according to the parameters.
#RestController
public class Controller {
#Autowired
private MyClass myClass;
#GetMapping(path = "/")
public String doSomething() {
String filter = myClass.foo();
return filter;
}
#GetMapping(path = "/two")
public String doSomething2(#RequestParam Map<String, String> allParams) {
String accountId = allParams.get("account_id");
String filter = MyClass.getInstance(K.BAR + accountId).foo();
return filter;
}
}
The bean is autowired because its use is greater than instantiation by the getInstance() method. In addition, the instantiation by the getIntance() method is variable according to the parameter. Don't ask me why the MyClass class is like this, because the API was old and I'm slowly refactoring.
The issue is that the autowired bean is correctly mocked by PowerMockito.mockStatic(MyClass.class) and also by #MockBean (which I used initially), but the call MyClass.getInstance() in Controller.class does not work at all.
I think the problem should happen when Spring climbs its environment and does not load everything that has been correctly mocked by PowerMockito, just the classes of its beans. Can anyone help me solve this problem?
This is just a wild guess, have you tried using regular Mockito as opposed to BDDMockito? Just want to rule it out as a culprit.
I have a service which I am trying to inject across various classes in my tests but I am getting its instance as null.
My config interface:
MyService.java
public interface MyService {
public String getHostUri();
}
My implementation class of this interface: MyServiceImpl.java
public class MyServiceImpl implements MyService {
private static final String BASE_HOST_URI_CONFIG = "localhost:4444";
#Override
public String getHostUri() {
return BASE_HOST_URI_CONFIG;
}
My Spring configuration class with the bean:
#Configuration
public class AutomationSpringConfig {
#Bean
public MyService getMyService(){
return new MyServiceImpl();
}
}
My testNG class:
#ContextConfiguration(classes=AutomationSpringConfig.class ,loader =AnnotationConfigContextLoader.class)
public class BasicAutomatedTest extends AbstractTestNGSpringContextTests {
private static final Logger LOGGER = Logger.getLogger(BasicAutomatedTest.class);
#Inject
private MyService myService;
#Test
public void basicTest {
Setup setup = new Setup();
LOGGER.info(myService.getHostUri());
LOGGER.info(setup.myService.getHostUri());
}
}
My helper class in which I am not able to get the injection:
public class Setup {
#Inject
public MyService myService;
}
So when I try to get the hostUri via the setup object in the BasicAutomatedTest's basicTest method I get a NullPointerException.
So I am not able to inject the MyService bean in the Setup class.
In order to use annotations you need to specify that behaviour in your beans XML configuration file. Something like this:
<context:component-scan base-package="your.base.package"/>
<context:annotation-config/>
Hope it helps!
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.