Spring AOP - #Before not executing - java

I'm trying to implement a simple Spring AOP (v4) example using #Before advice with an in-place pointcut expression, but the aspect method is not invoked. I have all the required dependencies(spring-aop, aopalliance, aspectweaver). What am I doing wrong?
package com.xyz;
public class TestClass {
#PostConstruct
public void init() {
test();
}
public void test() {
...
}
}
The aspect:
#Aspect
#Component
public class MyAspect{
#Before("execution(* com.xyz.TestClass.test())")
public void beforeTest() {
...
}
}

The reason why AOP isn't executed is because the TestClass.test() is not invoked in spring context but has simple / plain invocation from TestClass.init().
To test your setup modify it to something similar to below so that the TestClass.test() invocation is managed by spring
package com.xyz;
public class TestClass {
public void test() {
...
}
}
Inject the TestClass into another class say AnotherTestClass and invoke test method from there
package com.xyz;
public class AnotherTestClass {
#Autowired
private TestClass testClass;
public void anotherTest() {
testClass.test();
}
}

Related

How to mock double autowired class

In the following case, can I test "MainServiceImpl"?
【What I want to do】
・Test target object is "MainServiceImpl".
・SubMainServiceImpl is used without mock.
・SubSubMainServiceImpl.subSubSayHello method is used with mock. 
You may say "double autowired class is not recommended to mock." I know, but I want to know the above test is technically possible.
//Test Target Object
#Service
public class MainServiceImpl implements MainService {
#Autowired
private SubMainService subMainService;
#Override
public String mainSayHello() {
return "MainSayHello. Also..." + subMainService.subSayHello();
}
}
//MainServiceImpl depends on this class.
#Service
public class SubMainServiceImpl implements SubMainService {
#Autowired
private SubSubMainService subSubMainService;
#Override
public String subSayHello() {
return "SubSayHello. Also..." + subSubMainService.subSubSayHello();
}
}
//SubSubServiceImpl depends on this class.
#Service
public class SubSubMainServiceImpl implements SubSubMainService {
#Override
public String subSubSayHello() {
return "SubSubSayHello";
}
}
As a side note, I can mock direct-autowired class.
How can I mock "double" autowired class?
//Direct(not double) autowired class is mocked.
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MockMainServiceTest {
#InjectMocks
MainServiceImpl mainService;
#Mock
SubMainService subMainService;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void SubMainService_Mocked(){
doReturn("SubMainService_Mocked").when(subMainService).subSayHello();
Assert.assertThat(mainService.mainSayHello() ,is("MainSayHello. Also...SubMainService_Mocked"));
}
}
Technology
SpringBoot 2.5.4
JUnit 4.2
Java 1.8

JUnit test for ApplicationReadyEvent in spring boot app

I tried to write test for my spring boot application.
My application has business logic, which start after spring app has been initialized.
There is need to test triggeration of method with annotation #EventListener(ApplicationReadyEvent.class)
Below is a simple example that doesn't work. I expect that inscription "Testing..." appears in the console.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {
MySpringBootTest.MyTestConfig.class
})
public class MySpringBootTest {
#Test
public void test() {
}
#Configuration
public static class MyTestConfig {
#EventListener(ApplicationReadyEvent.class)
public void init() {
System.out.println("Testing...");
}
}
}
how do I make this example work?
Because you are using #ContextConfiguration Spring application Context is partially loaded and you don't have access to every capability of Spring application Context, however There are many ways to achieve something you want to do. One of them is using TextExecutionListener. I will show you how to use that in both Junit 4 and Junit 5 (jupiter):
Junit 5 (jupiter):
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes= MySpringBootTest.MyTestConfig.class)
#TestExecutionListeners(listeners = {MySpringBootTest.MyTestConfig.class})
public class MySpringBootTest {
#Test
public void test1() {
....
}
#Test
public void test2() {
...
}
#Configuration
public static class MyTestConfig extends AbstractTestExecutionListener {
#Override
public void beforeTestClass(TestContext testContext) throws Exception {
System.out.println("Testing...");
testContext.getApplicationContext(); //Do anything you want here
}
}
}
Here is a quote from Java doc for beforeTestClass method of TestExecutionListener:
Pre-processes a test class before execution of all tests within
the class. This method should be called immediately before
framework-specific before class lifecycle callbacks.
From the testContext that will be passed to this method you will have access to the application context and test class itself, you can do every thing you want with the test class there.
Junit 4:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {MySpringBootTest.MyTestConfig.class})
#TestExecutionListeners(listeners = {MySpringBootTest.CustomTestExecutionListener.class,
SpringBootDependencyInjectionTestExecutionListener.class})
public class MySpringBootTest {
#Test
public void test1() {
....
}
#Test
public void test2() {
...
}
#Configuration
public static class MyTestConfig {
}
public static class CustomTestExecutionListener extends AbstractTestExecutionListener {
#Override
public void beforeTestClass(TestContext testContext) throws Exception {
System.out.println("Testing...");
testContext.getApplicationContext(); //Do anything you want here
}
}
}

Spring Boot run controller without request

Is there a way to run a controller for initializing some data before Spring Boot starts the Tomcat?
My current code looks like that:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
AbstractApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
Controller controller = (Controller) context.getBean("controller");
controller.start();
context.close();
SpringApplication.run(Application.class, args);
}
}
#Controller
#Component("controller")
public class Controller {
#Autowired
private Runner runner;
public void start() {
runner.test();
}
}
#Configuration
#PropertySource("classpath:config.properties")
#Component("runner")
public class Runner {
#Value("${name}")
private String name;
public void test() {
System.out.println("hello " + name)
}
public String getName() {
return name;
}
}
#Controller
public class HelloController {
#Autowired
private Runner runner;
#RequestMapping("/hello")
public CalenderCollection data(#PathVariable("name")String name, Model model) {
model.addAttribute("name", runner.getName());
return "hello";
}
}
#Configuration
#ComponentScan(basePackages = "com.test")
public class AppConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
This prints the correct name into the console. But when I visit the url then runner is null. Then I thought about to change the Application and Controller class to this:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
#Controller
#Component("controller")
public class Controller {
#Autowired
private Runner runner;
public Controller() {
runner.test();
}
}
But now I have the problem that runner is null right in the beginning. What would be a right way to collect some data in the beginning and then continue with the process?
Usually you use ApplicationRunner or CommandLineRunner to run some code before application started.
From documentation
If you need to run some specific code once the SpringApplication has
started, you can implement the ApplicationRunner or CommandLineRunner
interfaces. Both interfaces work in the same way and offer a single
run method which will be called just before SpringApplication.run(…​)
completes.
The CommandLineRunner interfaces provides access to application
arguments as a simple string array, whereas the ApplicationRunner uses
the ApplicationArguments interface discussed above.
import org.springframework.boot.*
import org.springframework.stereotype.*
#Component
public class MyBean implements CommandLineRunner {
public void run(String... args) {
// Do something...
}
}
If you are just trying to run some code when the application has started, then there is no need to use Controller. Spring provides various application lifecycle hooks for such use cases.
The code would most likely look like this
#Component
public class MyListener
implements ApplicationListener<ContextRefreshedEvent> {
#Autowired
private Runner runner;
public void onApplicationEvent(ContextRefreshedEvent event) {
runner.test();
}
}
Check out this blog post and this part of the documentation for more information
If you want to initialize some values you can do something like this :
#SpringBootApplication
public class Application implements CommandLineRunner {
#Override
public void run( String... args ) throws Exception {
//initialise your value here
}
}
If this is something that affects only that class you can use
#PostConstruct
on a method of your controller class.
If this is something that is linked to the whole application, you should consider
creating an application listener on ApplicationReadyEvent

Inject an EJB into JUnit test class

I defined an EJB as follows:
#Stateless
#LocalBean
public class Foo {
#Inject
private Boo boo;
public void doSomething() {
boo.doOther();
}
}
And:
#Named
#RequestScope
public class Boo {
public void doOther() {
// I do, I do...
}
}
I would like to inject the Foo EJB into a JUnit test class:
import org.junit.*
public class FooTest {
#EJB
private Foo foo;
#Test
public void doSomethingTest() {
foo.doSomething();
assertTrue(true);
}
}
... But this code returns a NullPointerException.
What's wrong? How can I properly define that test by using Java EE CDI?

Is it possible to create nested unit test using junit and mockito?

For example:
#RunWith(MockitoJUnitRunner.class)
public class ClientFormServiceTest {
#Mock
ClientFormService clientFormService;
public class GetNewClientFormTest {
#Mock
protected ClientForm result;
#Before
public void given() {
result = clientFormService.getNewForm();
}
#Test
public void should_do_something() {
}
}
public class CreateClientFormTest {
#Mock
protected ClientForm clientForm;
#Before
public void given() {
clientFormService.createForm(clientForm);
}
#Test
public void should_do_something() {
}
}
}
This is what I want to do but I can't run the unit tests if are nested to a class.
I'm the author of a JUnit TestRunner, junit-nested, which I believe may do what you want: https://github.com/avh4/junit-nested
However, from your example it's not clear why you need nested tests. The typical reason to use them is to share setup behavior, but you should consider if having separate test classes is more appropriate.
In any case, here's how you can do it with junit-nested: (Since Nested is a test runner, you'll have to use MockitoAnnotations.initMocks() instead of the Mockito test runner.)
import net.avh4.test.junit.Nested;
#RunWith(Nested.class)
public class ClientFormServiceTest {
#Mock
ClientFormService clientFormService;
#Before
public void given() {
MockitoAnnotations.initMocks(this);
}
public class GetNewClientFormTest {
#Mock
protected ClientForm result;
#Before
public void given() {
MockitoAnnotations.initMocks(this);
result = clientFormService.getNewForm();
}
#Test
public void should_do_something() {
}
}
public class CreateClientFormTest {
#Mock
protected ClientForm clientForm;
#Before
public void given() {
MockitoAnnotations.initMocks(this);
clientFormService.createForm(clientForm);
}
#Test
public void should_do_something() {
}
}
}
Why would you like to do that? If you mean to benefit from code reuse among many similar tests, you could come up with a base test class with common code and make test classes extend it.

Categories