How to initialise Spring AnnotationConfigApplicationContext inside #BeforeTest in Testng? - java

I have a testng+spring suite with parallel option set to Tests. I would like to have each <test> have it's own ApplicationContext. So each <test> thread will have their own set of beans. I am able to initialise the ApplicationContext but the beans are not getting autowired and I am getting nullpointer exception when I am trying to access the bean. Please find my code below,
AppTest.class
#ComponentScan(basePackages = "org.comp.automation")
public class AppTest extends AbstractTestNGSpringContextTests{
#BeforeTest
public void intialise() throws Exception{
ApplicationContext context = new AnnotationConfigApplicationContext(BeanTwo.class);
}
#Autowired
public CommonBean commonBean;
#Autowired
public BeanTwo beanTwo;
#Parameters(value={"param"})
#Test
public void shouldAnswerWithTrue(String param) {
System.out.println(commonBean.STRING_CHECK);
commonBean.createCommonBeanObject(param);
System.out.println("Checking the bean values now...");
assertTrue( true );
}
}
CommonBean.class
#Component
public class CommonBean {
public String commonBeanValue;
public String STRING_CHECK = "Hello!!";
public void createCommonBeanObject(String param){
commonBeanValue = param;
}
public void printParamValue(){
System.out.println(commonBeanValue);
}
}
BeanTwo.class
#Component
public class BeanTwo{
public void printBeanTwo(){
System.out.println("Bean Two!!");
}
}
Can someone help me with this and point me in the right direction?

Related

#MockBean service field is always null in a Test class with #WebMvcTest

I'm trying to improve a unit test for a service I'm developing. I read somewhere that it's ideal to use #WebMvcTest annotation over #SpringBootTest when testing the Web or Controller layer.
However, for some reason, a #MockBean service field I am using in the Test class is always NULL.
java.lang.AssertionError: Expecting actual not to be null
In the test class below, serviceIsLoaded() method is always null when I run that single test.
SectionRESTControllerTest.java
#WebMvcTest
public class SectionRESTControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private SectionServiceImpl sectionServiceImpl;
#Test
public void serviceIsLoaded() {
assertThat(sectionServiceImpl).isNotNull();
}
}
SectionServiceImpl.java
#Service
public class SectionServiceImpl implements SectionService {
private final Logger logger = LoggerFactory.getLogger(SectionServiceImpl.class);
#Autowired
private SectionRepository sectionRepo; //saves to section table
#Autowired
private GradeLevelRepository gradeLevelRepo;
#Override
public Section createSection(Section section) {...}
#Override
public Section updateSection(Section request) throws Exception {...}
#Override
public Section getSectionById(Long id) {
return sectionRepo.findById(id).get();
}
#Override
public List<Section> getAllActiveSections() {
return sectionRepo.findSectionByIsActiveTrue();
}
#Override
public List<Section> getAllInActiveSections() {
return sectionRepo.findSectionByIsActiveFalse();
}
#Override
public List<Section> getSectionsByGradeLevelId(Long id) {
return sectionRepo.findByGradeLevelId(id);
}
#Override
public List<Section> getSectionByGradeLevelCode(String code) {
return sectionRepo.findByGradeLevelCode(code);
}
#Override
public List<Section> getSectionByGradeLevelCategory(String category) {
return sectionRepo.findByGradeLevelCategory(category);
}
}
My understanding is, with #WebMvcTest, it does not load the entire application context with all managed beans which makes the UnitTest run faster. Unlike, #SpringBootTest which loads everything when running the UnitTest.
SectionService.java
public interface SectionService {
Section createSection(Section section);
Section updateSection(Section section) throws Exception;
Section getSectionById(Long id);
List<Section> getAllActiveSections();
List<Section> getAllInActiveSections();
List<Section> getSectionsByGradeLevelId(Long id);
List<Section> getSectionByGradeLevelCode(String code);
List<Section> getSectionByGradeLevelCategory(String category);
}
Main class
#SpringBootApplication
public class AutoformSettingsServiceApplication {
public static void main(String[] args) {
SpringApplication.run(AutoformSettingsServiceApplication.class, args);
}
}
Do you have any thoughts or ideas why the #MockBean sectionServiceImpl is null
Thank you.

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.

Testing using spring boot throws null pointer exception

I am new to spring boot and i am trying to test a very simple class. But when i run the testMe() below I get exception below
java.lang.NullPointerException
at MyTest.testMe(MyTest.java:25)
at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37)
at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)
My understanding is when the context is loaded all the beans are initialized and object HelloWorld is created and are autowired in MyTest call. But helloWorld object is null at line helloWorld.printHelloWorld();
I need assistance here to understand what is missing.
#RunWith(MockitoJUnitRunner.class)
#SpringBootTest(classes = {AppConfigTest.class})
public class MyTest {
#Mock
#Autowired
private Message myMessage;
#Autowired
private HelloWorld helloWorld;
#Test
public void testMe(){
helloWorld.printHelloWorld();
}
}
#Configuration
public class AppConfigTest {
#Bean
public HelloWorld helloWorld() {
return new HelloWorldImpl();
}
#Bean
public Message getMessage(){
return new Message("Hello");
}
}
public interface HelloWorld {
void printHelloWorld();
}
public class HelloWorldImpl implements HelloWorld {
#Autowired
Message myMessage;
#Override
public void printHelloWorld() {
System.out.println("Hello : " + myMessage.msg);
}
}
public class Message {
String msg;
Message(String message){
this.msg = message;
}
}
You're running your tests with a runner that's not Spring-aware, so no wiring is happening. Look at the Spring Boot testing documentation, all their examples use #RunWith(SpringRunner.class). To mock a bean, annotate it with #MockBean, not #Mock. Make sure that the spring-boot-starter-test is included in your POM.

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();
}
}

Categories

Resources