Spring AOPed target class not injecting mocks - spring

I have class A having structure:
#Service
Class A implements AInterface {
private final C c;
String test(String b) {
}
}
Structure of class C:
class C {
// some methods
}
then I wrote interceptor for this class :
#Aspect
#Component
class Interceptor {
#Around(
value =
"execution(* AInterface.test(..)) && args(c)")
public Object intercept(ProceedingJoinPoint joinPoint, String c) {
// some logic
}
}
I am trying to do integration test and wants to inject mock class c in A but its not happening.
Test class structure:
#SpringBootTest
class ATest {
// Tried #MockBean also
#Mock
private C c;
#Autowired #InjectMock private AInterface a;
#BeforeTest {
MockitoAnnotations.initMocks(this);
// tried using ReflectionUtils to inject mock
}
#Test
void testTest () {
// when then logic
}
}

Related

Verifying pointcuts being called in tests

I have a dummy project where I try figure out how to test pointcuts being triggered.
My project consists of 1 aspect bean which just prints after a foo method is called
#Component
#Aspect
public class SystemArchitecture {
#After("execution(* foo(..))")
public void after() {
System.out.println("#After");
}
}
And a FooServiceImpl with implemented foo method
#Service
public class FooServiceImpl implements FooService{
#Override
public FooDto foo(String msg) {
return new FooDto(msg);
}
}
The code works and and I can see "#After" being printed to console, but I can't check programatically if after pointcut was called using the test below.
#SpringBootTest
public class AspectTest {
#Autowired
private FooService fooService;
#Test
void shouldPass() {
fooService.foo("hello");
}
}
I've also tried using non-bean proxy as was adviced in https://stackoverflow.com/a/56312984/18224588, but this time I'm getting an obvious error cannot extend concrete aspect because my spy proxy is no longer viewed as an aspect:
public class AspectNoContextTest {
#Test
void shouldPass() {
FooService fooService = Mockito.mock(FooService.class);
SystemArchitecture systemArchitecture = Mockito.spy(new SystemArchitecture());
AspectJProxyFactory aspectJProxyFactory = new AspectJProxyFactory(fooService);
aspectJProxyFactory.addAspect(systemArchitecture);
DefaultAopProxyFactory proxyFactory = new DefaultAopProxyFactory();
AopProxy aopProxy = proxyFactory.createAopProxy(aspectJProxyFactory);
FooService proxy = (FooService) aopProxy.getProxy();
proxy.foo("foo");
verify(systemArchitecture, times(1)).after();
}
}
Ok, after some digging, I found that it's possible to accomplish this by making an aspect a #SpyBean. Also AopUtils can be used for performing additional checks
#SpringBootTest
public class AspectTest {
#Autowired
private FooService fooService;
#SpyBean
private SystemArchitecture systemArchitecture;
#Test
void shouldPass() {
assertTrue(AopUtils.isAopProxy(fooService));
assertTrue(AopUtils.isCglibProxy(fooService));
fooService.foo("foo");
verify(systemArchitecture, times(1)).after();
}
}

Mocking a service in a Testcontainer Spring boot test

I am quite new in Spring and I am facing an issue right now with testing:
I have the following Service:
#Service
public class MyService {
public Integer getKey() {
List<Integer> keys = getKeys(1);
if (keys.size() == 1) {
return keys.get(0);
}
throw new IllegalArgumentException("Error!");
}
... and a getKeys() method, which provides a list based ona rest call...
}
And I use this service class in antother class:
#NoArgsConstructor
public class MyOtherClass extends MyClass {
#Autowired
private MyService myService;
....
#Override public KeyValue<Object, Object> doSomething(Object key, Object value) {
if (conditionIsTrue(key, value)) {
MyObject obj = new MyObject();
myObject.setKey(keyService.getKey()); ----- here is always null the keyService
.....
} else {
return KeyValue.pair(null, null);
}
}
And I try to write a test but the MyService is always null..
#ActiveProfiles("my-test")
#SpringBootTest(classes = Application.class)
#Testcontainers
#Slf4j
public class MyTest extends TestContext {
#BeforeEach
void init(final TestInfo testInfo) {
....
}
#AfterEach
void deinit() {
....
}
#Test
public void myTest() {
....
}
How can I inject a mock MyService into the test container?
Thank you!

How to mock lazy initialized Bean using Junit Mockito

I have a class where I autowired it using lazy initialization in constructor. But Iam unable to mock it using #Mock. It throws null pointer exception in my test class.
#Transactional
#Repository
public class A{
private B b;
#Autowired
public A(#Lazy B b {
this.b= b;
}
}
Iam unable to mock the bean B.My test class is as follows.
#RunWith(MockitoJUnitRunner.class)
public class ATest{
#Rule
public ExpectedException thrown = ExpectedException.none();
#InjectMocks
A a;
#Mock
B b;
Mockito.when(b.methodCall()).thenReturn("test");
}
The above code returns null pointer exception as Iam unable to mock class B.Please let me know how to mock this.
You are using constructor injection with #Autowired and #Lazy annotation should be at the place above the method. Please try :
Class A :
#Transactional
#Repository
public class A {
private B b;
#Autowired
#Lazy
public A(B b) {
this.b = b;
}
}
Class B :
#Component
public class B {
public String methodCall() {
return "foo";
}
}
Test class:
#RunWith(MockitoJUnitRunner.class)
public class MyTest {
#InjectMocks
private A a;
#Mock
private B b;
#Before
public void before() {
Mockito.when(b.methodCall()).thenReturn("test");
}
#Test
public void myTest() {
assertEquals(b.methodCall(), "test");
}
}
I am pretty sure it is not the best solution but I resolved it using reflection
#Before
public void before() {
ReflectionUtils.setField(ReflectionUtils.findRequiredField(A.class, "b"), a, b);
}

autowired #components null in unit test

I have a class:
#Component
public class B {
#Autowired
private A a;
}
and A is a component:
#Component
public class A{}
In unit test class BTest:
public class BTest {
#Test
public void testBMethod() {
}
}
I am not using an xml to define context or for beans to be picked from.
What is the cleanest way I can get the test to run?
You don't have to use Spring for the unit tests. Mockito may be used for this.
public class BTest {
#Mock
private A a;
#Mock
private B b;
#Test
public void testBMethod() {
}
}
For more details, you may check https://springframework.guru/mocking-unit-tests-mockito/
and https://dzone.com/articles/use-mockito-mock-autowired

How to initialize objects inside constructor of a class using spring framework?

I have following code in java:
public class A{
private B b;
private C c;
public A(){
b=new B();
c=new C();
c.foo(d,e);
}
}
I want to change the constructor such that i dont need to write the constructor at all and rather whenever an object of A is created, the spring configuration do it directly. I am new to spring and dont know how to proceed.
You can harness the dependency injection feature of Spring with the Autowired annotation. It has to be clear though, that in this case all involved class instances are singletons!
#Component
public class B {
}
#Component
public class C {
#PostConstruct
public void foo() {
}
}
#Component
public class A{
#Autowired
private B b;
#Autowired
private C c;
}
If this is not what you want, then Spring is not the right tool for this use case. To get rid of your constructor in A, you could use plain Java instead:
public class B {
}
public class C {
public C() {
foo();
}
public void foo() {
}
}
public class A{
private B b = new B();
private C c = new C();
}

Resources