How to setup TestExecutionListener in the application.properties - spring

I'm running a spring boot project with a large number of test and I want to use extent report. I have created a TestExecutionListener and I use the setting in one test.
I don't want to copy the same annotation in all test.
Where do I need to set the TestExecutionListener? and how?
Is it possible to set up in the application.properties?

The spring-test module declares all default TestExecutionListeners in its META-INF/spring.factories properties file.
Creating a simple Spring application:
MyBean:
#Component
public class MyBean {
public void doSomething() {
System.out.println("-- in MyBean.doSomething() method --");
}
}
AppConfig:
#Configuration
#ComponentScan
public class AppConfig {
}
Writing a TestExecutionListener:
public class MyListener implements TestExecutionListener {
#Override
public void beforeTestClass(TestContext testContext) throws Exception {
System.out.println("MyListener.beforeTestClass()");
}
#Override
public void prepareTestInstance(TestContext testContext) throws Exception {
System.out.println("MyListener.prepareTestInstance()");
}
#Override
public void beforeTestMethod(TestContext testContext) throws Exception {
System.out.println("MyListener.beforeTestMethod()");
}
#Override
public void afterTestMethod(TestContext testContext) throws Exception {
System.out.println("MyListener.afterTestMethod()");
}
#Override
public void afterTestClass(TestContext testContext) throws Exception {
System.out.println("MyListener.afterTestClass");
}
}
Writing JUnit test:
A TextExecutionListener can be registered via #TestExecutionListeners annotation:
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = AppConfig.class)
#TestExecutionListeners(value = {MyListener.class,
DependencyInjectionTestExecutionListener.class})
#TestPropertySource("/test.properties")
public class MyTests {
#Autowired
private MyBean myBean;
#Test
public void testDoSomething() {
myBean.doSomething();
}
}
Detailed infomation: https://www.logicbig.com/tutorials/spring-framework/spring-core/test-execution-listener.html
EDIT:
Declaring test property sources
Test properties files can be configured via the locations or value attribute of #TestPropertySource as shown in the following example.
Both traditional and XML-based properties file formats are supported — for example, "classpath:/com/example/test.properties" or "file:///path/to/file.xml".
Each path will be interpreted as a Spring Resource. A plain path — for example, "test.properties" — will be treated as a classpath resource that is relative to the package in which the test class is defined. A path starting with a slash will be treated as an absolute classpath resource, for example: "/org/example/test.xml". A path which references a URL (e.g., a path prefixed with classpath:, file:, http:, etc.) will be loaded using the specified resource protocol. Resource location wildcards (e.g. */.properties) are not permitted: each location must evaluate to exactly one .properties or .xml resource.
#ContextConfiguration
#TestPropertySource("/test.properties")
public class MyTests {
// class body...
}
More info: https://docs.spring.io/autorepo/docs/spring-framework/4.2.0.RC2/spring-framework-reference/html/integration-testing.html
https://www.baeldung.com/spring-test-property-source

Related

Intellij Spring: NoSuchBeanDefinitionException: No bean named 'accountDAO' available

This is driving me nuts. I have the following files, it is a very simple setup.
public class MainApp {
public static void main(String[] args) {
//read the spring config java class
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("Config.class");
//System.out.println("Bean names: " + Arrays.toString(context.getBeanNamesForType(AccountDAO.class)));
//get the bean from spring container
AccountDAO accountDAO = context.getBean("accountDAO", AccountDAO.class);
//call the business method
accountDAO.addAccount();
//close the spring context
context.close();
}
}
Config.java:
#Configuration
#ComponentScan("com.aop")
#EnableAspectJAutoProxy
public class Config {
}
LoggingAspectDemo.java:
#Aspect
#Component
public class LoggingAspectDemo {
//this is where we add all our related advices for the logging
//let's start with an #Before advice
#Before("execution(public void addAccount())")
public void beforeAddAccountAdvice() {
System.out.println("\n=======>>>> Executing #Before advice on method addAccount() <<<<========");
}
}
AccountDAO.java
#Component
public class AccountDAO {
public void addAccount() {
System.out.println(getClass() + ": Doing my Db work: Adding an account");
}
}
Everytime I run the MainApp.java, I get:
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'accountDAO' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:687)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1207)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:284)
All the files are under "com.aop" package so #ComponentScan should be scanning all the components. It looks simple enough but I can't get my hands around the problem, can anyone help me where I am going wrong?
You're invoking the constructor of AnnotationConfigApplicationContext with "Config.class" as String argument, but this constructor is actually for invoking with base packages i.e. the argument must be a package name.
Since you want to use it with the Configuration class, use the constructor which accepts Class instance instead i.e.
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);

#Profile Spring Annotation in Camel

I have a Spring Boot + Apache Camel project that works brilliantly. I just added a new bean though where I wanted to have its implementation be profile-specific. I created Spring tests to verify it, and it works as expected, but when I run the server I get the following stack trace:
Caused by: org.apache.camel.NoSuchBeanException: No bean could be found in the registry for: MyFancyBean
at org.apache.camel.component.bean.RegistryBean.getBean(RegistryBean.java:94)
at org.apache.camel.model.language.MethodCallExpression.createExpression(MethodCallExpression.java:196)
at org.apache.camel.model.language.MethodCallExpression.createPredicate(MethodCallExpression.java:210)
at org.apache.camel.model.language.ExpressionDefinition.createPredicate(ExpressionDefinition.java:148)
at org.apache.camel.model.ValidateDefinition.createProcessor(ValidateDefinition.java:63)
at org.apache.camel.model.ValidateDefinition.createProcessor(ValidateDefinition.java:35)
at org.apache.camel.model.ProcessorDefinition.makeProcessorImpl(ProcessorDefinition.java:545)
at org.apache.camel.model.ProcessorDefinition.makeProcessor(ProcessorDefinition.java:506)
at org.apache.camel.model.ProcessorDefinition.addRoutes(ProcessorDefinition.java:222)
at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:1068)
I have an interface and two implementations:
public interface MyFancyBean { ... }
public class FooFancyBean implements MyFancyBean { ... }
public class NonFooFancyBean implements MyFancyBean { ... }
Depending on profile, the correct bean is read instantiated:
#Configuration
public class AppConfig {
#Bean
#Profile("foo")
MyFancyBean fooBean() {
return new FooFancyBean();
}
#Bean
#Profile("!foo")
MyFancyBean nonFooBean() {
return new NonFooFancyBean();
}
}
I've verified this works a couple of ways. First, a couple tests:
#ActiveProfiles("anything-but-foo")
#RunWith(SpringJUnit4ClassRunner.class)
#ComponentScan(basePackages = {"com.example", "com.jtv.spring.boot"})
#EnableAutoConfiguration
#Component
public class NonFooBean_SpringTest {
#Autowired
private MyFancyBean bean;
#Test
// ... here "bean" is instantiated as "NonFooFancyBean"
So the test works.
Further, when I start my app, depending on profile the correct bean in my #Configuration class above is called.
But Camel is still angry and says "NoSuchBeanException" on startup.
FWIW, here's how I'm referencing the bean:
#Component
public class MyCamelRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
// [...]
from("direct:processStuff").
validate().method("MyFancyBean").
process("MyProcessor");
}
}
How do I get Camel to honor this config?
Whoooo... Y'all get to be my rubber duck today. I just autowired it. (This doesn't work for my processor, which is why it didn't occur to me initially.)
#Component
public class MyCamelRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
// [...]
#Autowired MyFancyBean myFancyBean;
from("direct:processStuff").
validate().method(myFancyBean).
process("MyProcessor");
}
}

Spring - How to know if cglib or jdk dynamic proxy was applied to a bean

Im studying for the Spring Core cert exam, and i'm doing some testing of the framework.
I'd like to know if there is a way to know if a Bean was proxied by CGLIB or the JDK library.
I already know the basic concepts like if you declare a Bean using the interface Spring will use the JDK to proxy it (unless you tell it otherwise). And if you declare a bean directly on a class it will proxy it by inheritance using CGLIB.
What I would like to know is what should I look for while debugging to check which library was used.
Given the following code, when I debug it, I dont see any difference in the instances of the beans created. I was expecting to see something like ConcreteBean$CGLIB in the bean that has no interface...
EDIT: i now understand that proxies are only created by spring when functionality needs to be added by a PostProcessor, but still, i'd like to know what to look for in the debugger to find if CGLIB was applied or not.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = MainConfig.class)
public class ProxiesTest {
#Autowired
RandomBean randomBean;
#Autowired
ConcreteBean concreteBean;
public void setUp() {
}
#Test
public void randomBeanTest() {
randomBean.doSomething();
}
#Test
public void concreteBeanTest() {
concreteBean.doSomething();
}
}
public class ConcreteBean {
public void doSomething() {
String concreteBean = "hello";
}
#PreDestroy
public void destroy() {
System.out.print("ConcreteBean Destroy");
}
}
public interface RandomBean {
public void doSomething();
public void destroy();
}
public class RandomBeanImpl implements RandomBean {
#Autowired
ApplicationContext context;
public void doSomething() {
context.getParentBeanFactory();
}
public void destroy() {
System.out.print("RandomBean destroyed");
}
}
#Configuration
#ComponentScan(basePackages = "com.certification.postprocessors")
public class MainConfig {
#Bean
public ConcreteBean concreteBean(){
return new ConcreteBean();
}
#Bean
public RandomBean randomBean() {
return new RandomBeanImpl();
}
}
When a bean is wrapped by a Spring CGLIB proxy it states $$EnhancerBySpringCGLIB.
A JDK proxy is shown as $Proxy
It looks like this in the debugging console

why can't I access ApplicationContext from ApplicationContextAware implemented bean

I have a Spring JUnit tester class MySimpleTester:
#
RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"classpath:/spring/mySimpleConfig.xml"})
public class MySimpleTester {
#Before
public void setUp() throws Exception {
myAdapter = (MyAdapter) applicationContext.getBean("myAdapter");
}
#test
public void testGetSimpleList() {
List<SimpleLink> simpleList = **myAdapter.getSimpleLinksList**();
}
...
...
In the adapter class I have:
public MyAdapter {
public List<SimpleLink> getSimpleLinksList() {
List<SimpleLink> simLinks = null;
String environment = AppFactory.getPropertiesObj();
...
...
class AppFactory implements ApplicationContextAware {
private static ApplicationContext context;
public void setApplicationContext(ApplicationContext acontext) {
context = acontext;
}
public getPropertiesObj() {
return getAppContext().getBean("propertiesBean");
}
I get NullPointerException and see that ApplicationContext is Null here.
However at the SpringJUnitTestRunner class MySimpleTester I could find the applicationContext to be initialized correctly. I am not including the mySimpleConfig.xml and included files. The method in MyAdapter class getSimpleLinksList() works perfectly fine from the web application when run in the application server, and the appcontext is obtained there.
Only from the Spring tester is it not able to reach the static application context AppFactory class, as it is called statically through AppFactory.getPropertiesObj(). I had the classpath set correctly as other test classes are executing.
If you want to access the current ApplicationContext in MySimpleTester:-
public class MySimpleTester {
#Autowired
ApplicationContext applicationContext;
#Before
public void setUp() throws Exception {
myAdapter = (MyAdapter) applicationContext.getBean("myAdapter");
}
#test
public void testGetSimpleList() {
List<SimpleLink> simpleList = **myAdapter.getSimpleLinksList**();
}
I think it is happening as multiple application contexts are created. The AplliCationContext object is supposed to be singleton. But when from the static method we call the applicationContext again it is refering to altogether different confirguration. The ApplicationContext is not even initialised there.
This does not happen when the same module is called from Spring MVC webcontanier. It happens only when you try to use Spring tester classes RunWith(SpringJUnit4ClassRunner.class). I can pass the AppContext in the business method but I do not want to change the bsiness method signature. I found some threads in spring community with similar issue.

Spring Boot - using Externalized Configuration values in #Configuration classes

I needed to externalize our session storage, so have used spring-session.
Following their examples at https://github.com/spring-projects/spring-session/blob/master/samples/boot/src/main/java/sample/config/EmbeddedRedisConfiguration.java, I created my EmbeddedRedisConfiguration and everything works as it should.
I decided that I wanted optional support to specify the Redis executable path, in the case of pre existing local redis server, so I have added to /resources/config/application.properties the following key value redis.embedded.executable.path==/path/to/redis.
My immediate thought was then to just use #Value annotation in my configuration, and have access to the value
static class RedisServerBean implements InitializingBean, DisposableBean, BeanDefinitionRegistryPostProcessor {
private RedisServer redisServer;
#Value("${redis.embedded.executable.path}")
String executablePath;
public void afterPropertiesSet() throws Exception {
if (executablePath != null) {
redisServer = new RedisServer(new File(executablePath), Protocol.DEFAULT_PORT);
} else {
redisServer = new RedisServer(Protocol.DEFAULT_PORT);
}
redisServer.start();
}
public void destroy() throws Exception {
if(redisServer != null) {
redisServer.stop();
}
}
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {}
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}
}
However, executablePath is always null. As you know, if you use an #Value in a #Service class or equivalent, the value will be populated.
I assume that this configuration is being invoked before the beans that load the properties, but I also know this is possible, because eg #DatasourceAutoConfiguration can use spring.datasource.* properties
I am obviously overlooking something simple here. Do I require my own #ConfigurationProperties
Change your property file to:
redis.embedded.executable.path=/path/to/redis

Resources