I'm getting BeanCreationException when using #AutoWired (Spring Annotation) and #PrepareForTest (PowerMock) and running my Spring enabled TestNG test.
I have a Spring controller, picked up via component scan.
I'm testing with TestNG, Mockito, and PowerMock.
I'm trying to spy on an auto wired controller thats autowired into the test, via: #AutoWired annotation.
Here's the beginning of the test class:
#PowerMockIgnore("*")
#WebAppConfiguration
#ContextConfiguration(locations = { "classpath:applicationContext-test.xml" })
#PrepareForTest(IWantAHamburgerController.class)
public class IWantAHamburgerControllerTest extends AbstractTestNGSpringContextTests {
#Autowired
private WebApplicationContext wac;
#Autowired
private MockHttpSession session;
#Autowired
private MockHttpServletRequest request;
#Autowired
private IWantAHamburgerController iWantAHamburgerController;
private MockMvc mockMvc;
#ObjectFactory
public IObjectFactory getObjectFactory() {
return new org.powermock.modules.testng.PowerMockObjectFactory();
}
#BeforeClass
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
// see the note at the bottom of this post about this line
//iWantAHamburgerController = (IWantAHamburgerController) applicationContext.getBean("iWantAHamburgerController");
}
I'm trying to test a GET method on IWantAHamburgerController. This is what the test looks like:
#Test
public void testGetHamburgerAfterAskingThisQuestion() throws Exception {
Principal p = PowerMockito.mock(Principal.class);
PowerMockito.when(p.getName()).thenReturn("oneofthefiveguys");
IWantAHamburgerController spy = PowerMockito.spy(iWantAHamburgerController);
PowerMockito.doReturn("oneofthefiveguys").when(spy).getUserName("oneofthefiveguys");
mockMvc.perform(get("/hamburgers/everythinghamburger.html")).andExpect(status().isOk())
.andExpect(view().name("jsp/hamburger/everythinghamburger"))
.andExpect(forwardedUrl("jsp/hamburger/everythinghamburger"));
PowerMockito.verifyPrivate(spy).invoke("initGrill", "oneofthefiveguys");
new org.mockito.internal.debugging.MockitoDebuggerImpl().printInvocations(spy);
}
Inside the test I want to spy on the autowired iWantAHamburgerController in order to verify that initGrill was called by the GET method on the controller.
If I remove #PrepareForTest(IWantAHamburgerController.class) I do not get a BeanCreationException, but then PowerMock doesn't work.
Note: I've tried to manually set the iWantAHamburgerController bean, but when I do, I get a ClassCastException.
Here's the full stack:
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name
'com.fiveguys.controllers.IWantAHamburgerControllerTest': Injection of
autowired dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not
autowire field: private
com.fiveguys.controllers.IWantAHamburgerController
com.fiveguys.controllers.IWantAHamburgerControllerTest.iWantAHamburgerController;
nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type
[com.fiveguys.controllers.IWantAHamburgerController] found for
dependency: expected
Related
I am writing a test for a very simple standalone Controller:
#CrossOrigin(origins = "*", maxAge = 3600)
#RestController
public class TestController {
#PostMapping("/version")
public String getVersion() {
// String a = TUtil.TestUtil("ds");
String a = "a";
return a;
}
}
This controller only defines and returns a String, it is not dependent on any other classes.
Here is my test:
#RunWith(SpringRunner.class)
#WebMvcTest(TestController.class)
public class TestControllerTest {
#Autowired
private MockMvc mockMvc;
#Test
public void getVersion() throws Exception {
this.mockMvc.perform(MockMvcRequestBuilders.post("/version"))
.andExpect(MockMvcResultMatchers.status().is4xxClientError())
.andDo(MockMvcResultHandlers.print())
.andExpect(MockMvcResultMatchers.content().string("a"))
.andReturn();
}
}
then it gives a lot of errors, some of them are:
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'ipArcuserauthMapper' defined in file [/Users/xy/Desktop/springweb/aaa/dccb/target/classes/com/dccb/tft/mapper/IpArcuserauthMapper.class]:
Invocation of init method failed;
nested exception is java.lang.IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required
It says I need to define a bean of type 'IpArcuserauthMapper' which has nothing remotely to do with the TestController.
In another case, if I use the SpringbootTest annotation, the problem can be solved:
#SpringBootTest(classes = {TftApplication.class})
#AutoConfigureMockMvc
#RunWith(SpringRunner.class)
I have no idea what is going on with #WebMvcTest(TestController.class)??
From what I know the WebMvcTest annotation only scans the class defined in the brackets.
Please help !!
I am trying to load the JobLauncherTestUtils object in a JUnit 5 and SpringBatchTest annotation. However, it fails to load the application context. All the other autowired beans load successfully, but the JobLauncherTestUtils fails to load. Here is my test configuration, omitting the imports. I tried manually loading it in BeforeAll but then the JobRepository and JobLauncher fail to load. I am only interested in being able to instantiate JobLauncherTestUtils successfully. Please help!
#ExtendWith(SpringExtension.class)
#ExtendWith(MockitoExtension.class)
#SpringBatchTest
#TestExecutionListeners({DependencyInjectionTestExecutionListener.class ,
DirtiesContextTestExecutionListener.class})
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
#EnableAutoConfiguration
public class ProductsProcessorTest {
#Autowired
JobLauncherTestUtils jobLauncherTestUtils;
#Autowired
private JobRepositoryTestUtils jobRepositoryTestUtils;
#MockBean
JobLauncher jobLauncher;
#Autowired
JobRepository jobRepository;
#Autowired
OrderManagementService orderManagementService;
#MockBean
Job keyLoaderJob;
#Autowired
#JobScope
static ProductsLoader productsLoader;
//Tried manually instantiating it, but then would l
#BeforeAll
static void setUp() throws Exception {
//jobLauncherTestUtils = new JobLauncherTestUtils();
}
//This does not work either
#BeforeEach
void init(){
// jobLauncherTestUtils.setJobLauncher(jobLauncher);
// jobLauncherTestUtils.setJobRepository(jobRepository);
}
....
}
Here is the exception I get:
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'jobLauncherTestUtils': Unsatisfied dependency expressed through method 'setJobRepository' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.batch.core.repository.JobRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
No qualifying bean of type 'org.springframework.batch.core.repository.JobRepository' available
This error means there is no JobRepository bean defined in your test application context. Make sure you import the class where this bean is defined.
When I try to run my tests they all fail becaouse they can't find the bean of one of my classes.
Here are my codes which are used in the context:
The exception I get is this:
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'testProtoAdminController' : Unsatisfied dependency expressed through constructor parameter 2; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'TestProtoCopyService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
TestProtoAdminControllerTest
#RunWith(SpringRunner.class)
#WebMvcTest(controllers = TestProtoAdminController.class)
public class TestProtoAdminControllerTest {
//Some used services
#Before
public void setUp() {
authenticatedMockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
#Test
#WithMockUser
public void testCopyProto() throws Exception {
authenticatedMockMvc.perform(post("/api/admin/{id}/copy", 1)
.contentType(MediaType.APPLICATION_JSON)
.content(asJson(new TestProtoBaseVo()))).andExpect(status().isOk());
}
//Some more tests which are not important in this case
TestProtoCopyService
#Service
public class TestProtoCopyServiceImpl implements TestProtoCopyService {
//Other services and repositories I have to use.
//Methods
}
TestProtoCopyService
public interface TestProtoCopyService {
#Transactional
void copyTestProto(long testProtoId, String sourceTenant, String targetTenant);
}
TestProtoAdminController
#RestController
#RequestMapping("/*")
public class TestProtoAdminController {
private TestProtoCopyService testProtoCopyService;
public TestProtoAdminController(TestProtoCopyService testProtoCopyService {
this.testProtoCopyService = testProtoCopyService;
}
When using #WebMvcTest Spring will prepare everything to test your web layer. This doesn't mean all your beans are scanned and are part of this test application context and ready to inject.
In general, you usually mock the service class of your controller with #MockBean and then use Mockito to specify its behavoir:
#RunWith(SpringRunner.class)
#WebMvcTest(controllers = TestProtoAdminController.class)
public class TestProtoAdminControllerTest {
#MockBean
private TestProtoCopyService mockedService
// the rest
#Before
public void setUp() {
authenticatedMockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
#Test
#WithMockUser
public void testCopyProto() throws Exception {
authenticatedMockMvc.perform(post("/api/admin/{id}/copy", 1)
.contentType(MediaType.APPLICATION_JSON)
.content(asJson(new TestProtoBaseVo()))).andExpect(status().isOk());
}
If you want Spring Boot to bootstrap the whole application context with every bean consider using #SpringBootTest. With this annotation, you can inject any bean to your application. The downside here is that you need to provide the whole infrastructure (database/queues/etc.) for your test.
Hi i was trying to work over an existing SpringBoot application. I created a service class and tried to autowire it in the existing controller, but when trying to build, its failing saying bean injection failed.
Cause: org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'controller': Injection of autowired
dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not
autowire field: private
com.disooza.www.card.dispenser.service.FilaPartnerService
com.disooza.www.card.dispenser.controller.CardDispenserController.FilaPartnerService;
nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type
[com.disooza.www.card.dispenser.service.FilaPartnerService] 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)}
at
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334)
Following is my controller class:
#Controller
#RequestMapping(value = "/service")
public class CardController {
private static final Logger LOGGER = LoggerFactory.getLogger(CardController.class);
#Autowired
private CardDao dao;
#Autowired
private PaymentService paymentService;
#Autowired
private FilaPartnerService filaPartnerService;
FilaPartnerService is the newly created interface, and rest all autowires are working fine in this controller.
Interesting thing is when I try to place this service class in any other controller it is working fine. Any help over this issue will be appreciated, since I'm stuck with it.
This is my service interface:
#Service
public interface FilaPartnerService {
RetrievePaymentTokenResponse retrieveXXX(SupplierRequest request);
}
This is the implementation class:
#Component
public class FilaPartnerServiceImpl implements FilaPartnerService {
#Autowired
private RestTemplate restTemplate;
#Autowired
private RetrieveRequestBuilder retrieveRequestBuilder;
#Value("${filaPartner.url}")
private String filaServiceUrl;
#Override
public RetrievePaymentTokenResponse retrieveFilaPaymentToken(SupplierTokenRequest request) {
RetrievePaymentTokenResponse tokenResponse = null;
RetrievePaymentTokenRequest paymentServiceRequest = retrievePaymentTokenRequestBuilder.retrievePaymentTokenRequestBuilder(request);
try {
tokenResponse =
restTemplate.postForObject( FilaServiceUrl, paymentServiceRequest, RetrievePaymentTokenResponse.class);
} catch (RestClientException exp) {
//TO-DO return error code
}
return null;
}
}
I'm struggling with Cucumber and Spring configuration.
I'm writing selenium framework using Page Object Pattern, with BrowserFactory.
When I use #ComponentScan, #Component and #Autowire annotations everything works fine, but when I want to create a bit more complicated bean with #Bean annotation (BrowserFactory which registers few browser drivers) in #Configuration class it does not work, during debug I'm getting nulls on every single variable I'm trying to Autowire.
I'm using Spring 4.2.4, all cucumber dependencies in version 1.2.4.
Config:
#Configuration
public class AppConfig {
#Bean
#Scope("cucumber-glue")
public BrowserFactory browserFactory() {
BrowserFactory browserFactory = new BrowserFactory();
browserFactory.registerBrowser(new ChromeBrowser());
browserFactory.registerBrowser(new FirefoxBrowser());
return browserFactory;
}
#Bean(name = "loginPage")
#Scope("cucumber-glue")
public LoginPage loginPage() throws Exception {
return new LoginPage();
}
#Bean(name = "login")
#Scope("cucumber-glue")
public Login login() {
return new Login();
}
}
POP:
public class LoginPage extends Page {
public LoginPage() throws Exception {
super();
}
...
}
Page:
public class Page {
#Autowired
private BrowserFactory browserFactory;
public Page() throws Exception{
...
}
}
Login:
public class Login {
#Autowired
private LoginPage loginPage;
public Login(){}
...
}
Steps:
#ContextConfiguration(classes = {AppConfig.class})
public class LoginSteps {
#Autowired
Login login;
public LoginSteps(){
}
#Given("^an? (admin|user) logs in$")
public void adminLogsIn(Login.User user) throws Exception {
World.currentScenario().write("Logging in as " + user + "\n");
login.as(user);
}
}
Error:
cucumber.runtime.CucumberException: Error creating bean with name 'LoginSteps': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: Login LoginSteps.login; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'login': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private LoginPage Login.loginPage; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'loginPage' defined in AppConfig: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [LoginPage]: Factory method 'loginPage' threw exception; nested exception is java.lang.NullPointerException
And now for the fun part...
BrowserFactory in World class is properly Autowired!!
World:
public class World {
#Autowired
private BrowserFactory browserFactory;
...
}
So I'll answer my own question:)
Issue was that I was calling BrowserFactory inside of Page constructor.
Looks like this bean was not yet created and was causing NPEs.
In order to fix that I:
Added #Lazy annotation to configuration (all elements that use this configuration, both defined in that class and those which will be found by Scan will be created as Lazy)
Moved call to Browser Factory to #PostConstruct method
Two more things to increase readability of Spring config:
Added #ComponentScan to configuration
Classes with no constructor parameters are annotated with #Component and #Scope("cucumber-glue") annotation so bean creation can be removed from AppConfig.class