Spring Junit4TestRunner Autowired null - java

public interface Animal {
public String getName();
public int getAge();
}
#Component
public class Dog implements Animal{
#Override public String getName() {
return "Puppy";
}
#Override public int getAge() {
return 10;
}
}
#Component("cdiExample")
public class CDIExample {
#Autowired
private Dog dog;
public void display() {
try {
System.out.println("com.example.Animal ---> " + dog.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:beans.xml");
Animal animal=context.getBean("dog", Animal.class);
System.out.println(animal.getName());
}
}
Application Context
<context:annotation-config/>
<context:component-scan base-package="com.example"/>
Junit Test
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath*:test-beans.xml" })
public class CDIExampleTest {
//#Autowired
private CDIExample cdiExample;
#Before
public void before() throws Exception {
cdiExample = new CDIExample();
}
#Test
public void testDisplay() throws Exception {
cdiExample.display();
}
}
Test-context
<import resource="classpath*:/beans.xml" />
If i run the above Junittestcase, autowire is null.
If i execute the main method and Using ClassPathXmlApplicationContext, bean is loading and autowire is not null.

the problem seems to be cdiExample in you test case not being a spring bean. You are manually instantiating it in #Before.
Instead try this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath*:test-beans.xml" })
public class CDIExampleTest {
#Autowired
private CDIExample cdiExample;
#Test
public void testDisplay() throws Exception {
cdiExample.display();
}
}
This way the cdiExample will be injected from the spring context which will have dog autowired by spring.

Related

Spring boot testing problem with #Autowire

I am new to spring boot testing. I have error related to loading application context when I am trying to test some methods of below AwsTestsExtractor class.
Error message:
Field awsTestsExtractor in com.silvio.me.Prototype required a bean of
type 'com.silvio.me.AwsTestsExtractor' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.silvio.me.AwsTestsExtractor' in
your configuration.
Code:
#Component
public class AwsTestsExtractor extends TestsExtractor {
#Autowired
private ExaminationRepository examinationRepository;
public AwsTestsExtractor() { }
...
...
private String getTestDbRef(String description) {
ArrayList<Examination> strArr = new ArrayList<>(examinationRepository.customQuery(description));
if(strArr.size() > 0)
return strArr.get(0).getName();
else
return null;
}
}
#SpringBootApplication
public class Prototype implements CommandLineRunner {
#Autowired
private AwsTestsExtractor awsTestsExtractor;
public static void main(String[] args) {
SpringApplication.run(Prototype.class, args);
}
#Override
public void run(String... args) throws Exception {
String document="src/main/resources/test2.jpg";
awsTestsExtractor.extract(document);
}
catch (Exception ex) {
System.out.println(ex.getMessage());
}
}
}
#RunWith(SpringRunner.class)
#TestPropertySource(locations = "classpath:application-integrationtest.properties")
#DataMongoTest
public class AwsTestsExtractorTest {
#Autowired
private MongoTemplate mongoTemplate;
#Autowired
private AwsTestsExtractor awsTestsExtractor;
#Before
public void setUp() {
mongoTemplate.save(new Examination("terefere"));
}
#Test
public void getTestDbRefTest() {
assertTrue(ReflectionTestUtils.invokeMethod(awsTestsExtractor, "getTestDbRef","terefere" ).equals(true));
}
}
I suppose I make some fundamental mistake, any help appreciated.

Listing Aspect-proxied beans in Spring

Is there a way to get the list of beans proxied with a specific Aspect by Spring?
We have an aspect on some beans that stopped working, and we are trying to figure out what happened, so I created a class to scan the ApplicationContext after it has been loaded
#Component
public class AspectScanner implements ApplicationListener<ContextRefreshedEvent> {
public static final Logger LOGGER = LoggerFactory.getLogger(AspectScanner.class);
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
final ApplicationContext applicationContext = event.getApplicationContext();
applicationContext.[GET PROXIED BEANS CALL];
}
}
Any suggestions?
To identify advised bean you should check if it implements org.springframework.aop.framework.Advised and use org.springframework.aop.aspectj.AspectJPrecedenceInformation#getAspectName to get aspect name. Proof of concept code is presented below.
#Configuration
#ComponentScan
#EnableAspectJAutoProxy
public class AspectScanner implements ApplicationListener<ContextRefreshedEvent> {
public static final Logger LOGGER = LoggerFactory.getLogger(AspectScanner.class);
public void onApplicationEvent(ContextRefreshedEvent event) {
final ApplicationContext applicationContext = event.getApplicationContext();
Map<String, Object> beansOfType = applicationContext.getBeansOfType(Object.class);
for (Map.Entry<String, Object> entry : beansOfType.entrySet()) {
boolean advisedWith = isAdvisedWith(applicationContext, entry.getValue(), BeanAspect.class);
LOGGER.info(entry.getKey() + (advisedWith ? " is advised" : " isn't advised"));
}
}
private static boolean isAdvisedWith(ApplicationContext context, Object bean, Class<?> aspectClass) {
boolean advisedWith = false;
HashSet<String> names = new HashSet<>(Arrays.asList(context.getBeanNamesForType(aspectClass)));
if (bean instanceof Advised) {
Advisor[] advisors = ((Advised) bean).getAdvisors();
for (Advisor advisor : advisors) {
if (advisor instanceof AspectJPrecedenceInformation) {
if (names.contains(((AspectJPrecedenceInformation) advisor).getAspectName())) {
advisedWith = true;
}
}
}
}
return advisedWith;
}
#Aspect
#Component
public static class BeanAspect {
#Before("execution(* test.AspectScanner.Bean*.*(..))")
public void beforeAny(JoinPoint jp) {
}
}
#Component
public static class Bean1 {
public void m() {
}
}
public interface Bean2Intf {
void m();
}
#Component
public static class Bean2 implements Bean2Intf {
public void m() {
}
}
#Component
public static class NotAdvised {
public void n() {
}
}
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AspectScanner.class);
context.start();
context.registerShutdownHook();
}
}

How to inject ANY information about test in spring testing?

I would like some of my beans know something about test. SOMETHING. May be test class name or some of it's methods.
For example, suppose my test class has a method
public String getTestName() {
return getClass().getSimpleName();
}
This method returns test name and can be overridden.
Is it possible to inject this name into some beans of Spring context, to use during test?
For example, with autowire feature:
#Autowired
public String testName;
not only in test class, but in other beans too.
UPDATE
Below are two (failed) attempts to implement injecting testInstance. May be there are some convenient ways to do that?
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = TestClassAwareTry._Config.class)
#TestExecutionListeners(value = { TestClassAwareTry._Listener.class },
mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS)
public class TestClassAwareTry {
/**
* Interface to tag beans, who want to know if they are in test
*/
public interface TestInstanceAware {
void setTestInstance(Object value);
}
/**
* Sample bean, which would like to know if it is in test
*/
public static class MyBean implements TestInstanceAware {
private Object testInstance;
{
System.out.println("MyBean constructed");
}
public void setTestInstance(Object value) {
this.testInstance = value;
System.out.println("testInstance set");
}
public Object getTestInstance() {
return testInstance;
}
}
/**
* Attempt to inject testInstance with a bean, implementing {#link BeanPostProcessor}
*/
public static class TestInstanceInjector implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if( bean instanceof TestInstanceAware ) {
TestInstanceAware aware = (TestInstanceAware) bean;
// we don't have access to test instance here
// otherwise I would write
//Object testInstance = getTestInstance();
//aware.setTestInstance(testInstance);
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
/**
* Attempt to inject testInstance with test execution listener
*/
public static class _Listener extends AbstractTestExecutionListener {
#Override
public void prepareTestInstance(TestContext testContext) throws Exception {
Object testInstance = testContext.getTestInstance();
ApplicationContext context = testContext.getApplicationContext();
// we don't have setBean() method
// I would write if I have
// context.setBean("testInstance", context);
}
}
/**
* Java-based configuration
*/
#Configuration
public class _Config {
#Bean
public MyBean myBean() {
return new MyBean();
}
#Bean
public TestInstanceInjector testInstanceInjector() {
return new TestInstanceInjector();
// I would acquire test instance here and pass it to constructor, if I can
}
}
#Autowired
public MyBean myBean;
#Test
public void testInjected() {
assertSame( this, myBean.getTestInstance());
}
}
I've ended up creating ContextCustomizerFactory that registers BeanPostProcessor
package com.company.testing.base.spring;
import java.util.List;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.test.context.ContextConfigurationAttributes;
import org.springframework.test.context.ContextCustomizer;
import org.springframework.test.context.ContextCustomizerFactory;
public class TestAwareContextCustomizerFactory implements ContextCustomizerFactory {
#Override
public ContextCustomizer createContextCustomizer(
Class<?> testClass, List<ContextConfigurationAttributes> configAttributes) {
return (context, mergedConfig) -> {
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.addBeanPostProcessor(
new TestInstanceAwareBeanPostProcessor(mergedConfig.getTestClass()));
};
}
}
TestInstanceAwareBeanPostProcessor
public class TestInstanceAwareBeanPostProcessor implements BeanPostProcessor {
private final Class<?> testClass;
TestInstanceAwareBeanPostProcessor(Class<?> testClass) {
this.testClass = testClass;
}
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof TestClassAware) {
((TestClassAware) bean).setTestClass(testClass);
}
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
resources/META-INF/spring.factories
# ContextCustomizerFactories for the Spring TestContext Framework
org.springframework.test.context.ContextCustomizerFactory = \
com.company.testing.base.spring.TestAwareContextCustomizerFactory
The only way I've been able to do this is by delaying creation of the subject until you are in the test method and to have the bean in the prototype scope.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { LiveConfig.class, DevConfig.class})
#ActiveProfiles("Dev")
public class MeTest {
#Autowired
public ApplicationContext context;
#Autowired
DevConfig devConfig;
#Rule
public TestName nameRule = new TestName();
#Before
public void setName() {
devConfig.setSettings(nameRule.getMethodName());
}
#Test
public void test() {
Bean subject = context.getBean(Bean.class);
System.out.println(subject.settings);
assertThat(subject.settings, is(nameRule.getMethodName()));
}
#Test
public void test2() {
Bean subject = context.getBean(Bean.class);
System.out.println(subject.settings);
assertThat(subject.settings, is(nameRule.getMethodName()));
}
}
#Configuration
class LiveConfig {
#org.springframework.context.annotation.Bean
public String getSettings() {
return "/some/real/file.txt";
}
#org.springframework.context.annotation.Bean
#Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Bean getBean() {
return new Bean();
}
}
#Configuration
class DevConfig {
private String settings;
#org.springframework.context.annotation.Bean
#Profile("Dev")
#Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public String getSettings() {
return settings;
}
public void setSettings(String settings) {
this.settings = settings;
}
}
class Bean {
public Bean() {
System.out.println("Bean");
}
String settings;
#Autowired
void setSettings(String settings) {
System.out.println("Settings: " + settings);
this.settings = settings;
}
}
This uses Profiles to change what Live sees and what the tests see, and the a NameRule to get the name. It is clunky.
I would NOT use the TestName rule, but rather the TemporaryFolder rule and use that to set whatever setting your application uses for the output folder. I'd also only use DI in a test in very rare cases (i.e. full blown integration tests).
Do you mean like this?
public class MyTest {
#Test
public void testName() {
MyBean b = new MyBean(MyTest.class.getSimpleName());
b.doSomething();
}
}
You can achieve this in a more elegant way using Spring Boot Auto configuration feature by making yours, this way:
define a Configuration class that exposes or registers your bean this way:
#Configuration
public class MyBeanProviderConfiguration {
#ConditionalOnMissingBean
#Bean
public MyBean myBean() {
// return a fully initialised MyBean instance
}
}
Then define a custom annotation Spring Boot like, say #AutoConfigureMyBean this way:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
#ImportAutoConfiguration(MyBeanProviderConfiguration.class)
public #interface AutoConfigureMyBean {}
Then you can use this in your Spring test, here is an example:
#RunWith(SpringRunner.class)
#AutoConfigureMyBean
public class MyTest {
#Autowired
MyBean myBean;
}
Or also declare your MyBean #Autowired dependent bean in a regular Spring test (using a Config class), A MyBean instance will be automatically injected into it.

#Autowired fails in spring boot web project

I have a simple Spring Boot web project, right from a template:
#SpringBootApplication
#RestController
public class HelloWorldRestApplication {
public static void main(String[] args) {
SpringApplication.run(HelloWorldRestApplication.class, args);
Performer p = new Performer();
p.perform();
}
}
I have a test to ensure autowiring works, and in fact it does in this test class (examples come from Spring in Action, 4th):
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes=CDPlayerConfig.class)
public class CDPlayerTest {
#Autowired
private CDPlayer cdp;
#Test
public void cdShouldNotBeNull(){
assertNotNull(cdp);
}
}
and:
public class Performer {
#Autowired
private CDPlayer cdp;
public void perform(){
System.out.println(cdp);
cdp.play();
}
public CDPlayer getCdp() {
return cdp;
}
public void setCdp(CDPlayer cdp) {
this.cdp = cdp;
}
}
and:
#Component
public class CDPlayer{
public void play(){
System.out.println("play");
}
}
config:
#Configuration
#ComponentScan
public class CDPlayerConfig {
}
However, it doesnt work in HelloWorldRestApplication, I get null.
Adding #ContextConfiguration(classes=CDPlayerConfig.class) doesn't help.
What do I miss?
Try enabling #ComponentScan your packages in your main class and get Performer class instance from ApplicationContext as below:
#SpringBootApplication
#RestController
#ComponentScan({“package.name.1”,”package.name.2”})
public class HelloWorldRestApplication {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(HelloWorldRestApplication.class, args);
Performer p = ctx.getBean(Performer.class);//get the bean by type
p.perform();
}
}

Mocking a class which uses static void method of another class

public class ProjectIdInitializer {
public static void setProjectId(String projectId) {
//load spring context which i want to escape in my test
}
}
public class MyService {
public Response create(){
...
ProjectIdInitializer.setProjectId("Test");
}
}
#RunWith(PowerMockRunner.class)
#PrepareForTest({ProjectIdInitializer.class})
public class MyServiceTest{
#InjectMocks
private MyService myServiceMock ;
public void testCreate() {
PowerMockito.mockStatic(ProjectIdInitializer.class);
PowerMockito.doNothing().when(ProjectIdInitializer.class, "setProjectId", Mockito.any(String.class));
// Does not work,still tries to load spring context
Response response=myServiceMock .create();
}
How can i make sure that nothing happens if ProjectIdInitializer.setProjectId() is called from myservice?
As stated in comments, you should be aware that many things might break because of PowerMock.
You need to use PowerMock runner, something like that:
#RunWith(PowerMockRunner.class)
#PrepareForTest(ProjectIdInitializer.class)
public class MyServiceTest{
private MyService myService = new MyService();
public void testCreate()
{
PowerMockito.mockStatic(ProjectIdInitializer.class);
PowerMockito.doNothing().when(ProjectIdInitializer.class, "setProjectId", Mockito.any(String.class));
Response response=myService.create();
}
}
see also this doc.
This self contained sample:
#RunWith(PowerMockRunner.class)
#PrepareForTest(A.ProjectIdInitializer.class)
public class A {
private MyService myService = new MyService();
#Test
public void testCreate() throws Exception {
PowerMockito.mockStatic(ProjectIdInitializer.class);
PowerMockito.doNothing().when(ProjectIdInitializer.class, "setProjectId", Mockito.any(String.class));
System.out.println("Before");
Response response = myService.create();
System.out.println("After");
}
public static class ProjectIdInitializer {
public static void setProjectId(String projectId) {
//load spring context which i want to escape in my test
System.out.println(">>>>>> Game over");
}
}
public static class Response {
}
public static class MyService {
public Response create() {
// ...
ProjectIdInitializer.setProjectId("Test");
return null;
}
}
}
outputs:
Before
After
As expected

Categories

Resources