JUnit method.getAnnotations(CustomAnnotation.class) throwing NullPointerException - java

I am struggling to write unit test cases for aspect code. Please find the all the respective code.
Custom Annotation -
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface WriteAccessAuthorization{
boolean isAdmin() default false;
}
Aspect Code -
#Aspect
class AccessAspect {
...
...
boolean isAdminForWriteAccess(ProceedingJoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
WriteAccessAuthorization writeAccessAuthorization =
method.getAnnotation(WriteAccessAuthorization.class);
return writeAccessAuthorization.isAdminPortal();
}
...
}
Here I am getting NPE in last line of the method.
Here method.getAnnotation() is returning null even we are mocking it in Junit test method.
Please find the junit test case code -
class AccessAspectTest {
#Mock private ProceedingJoinPoint joinPoint;
#Mock private MethodSignature methodSignature;
#Mock private Method method;
#Mock private WriteAccessAuthorization writeAccessAuthorization;
#InjectMocks private AccessAspect accessAspect;
#BeforeEach
public void setup() {
MockitoAnnotations.openMocks(this);
}
#Test
void test_isAdmin()
throws Throwable {
//Given
when(joinPoint.getSignature()).thenReturn(methodSignature);
when(methodSignature.getMethod()).thenReturn(getDeclaredMethod(WriteAccessAuthorization.class));
when(method.getAnnotation(WriteAccessAuthorization.class)).thenReturn(writeAccessAuthorization);
//When
accessAspect.isAdminForWriteAccess(joinPoint);
//Then
verify(joinPoint, times(1)).proceed();
}
#NotNull
private <T> Method getDeclaredMethod(Class<T> clazz) throws NoSuchMethodException {
return clazz.getDeclaredMethod("isAdmin");
}
}
In many blogs or stackoverflow answers it was mention to have RUNTIME policy in you annotation but in my case it was already placed.
Please let me know if there is anything else required.

You actually need to apply the annotation to a method. What your code is testing is whether the isAdmin method defined in annotation interface is annotated with WriteAccessAuthorization which it is not. That's why method.getAnnotation returns null.
Here is an example of how to access the annotation:
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface WriteAccessAuthorization {
boolean isAdmin() default false;
}
public static final class SomeClass {
#WriteAccessAuthorization
public void doSth() {}
}
public static void main(String[] args) throws Exception {
Method method = SomeClass.class.getDeclaredMethod("doSth");
WriteAccessAuthorization annotation =
method.getDeclaredAnnotation(WriteAccessAuthorization.class);
System.out.println(annotation);
}
Output:
#com.example.test$WriteAccessAuthorization(isAdmin=false)

Related

Mocking or testing an interface in Junit5

I have a CMS (Content management System) to store property key values.
public interface CMSConfig {
#Property(propertyName = "someConfig")
String getSomeConfig();
}
And the Configuration annotation code is
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
public #interface Configuration {
String configName() default "";
}
And the way to call this CMS is
#Service
public class MockitoService {
#ManagedConfiguration
private CMSConfig cmsConfig;
public String method() {
return "Hello!" + cmsConfig.getSomeConfig();
}
}
ManagedConfiguration.java
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.FIELD, ElementType.METHOD})
public #interface ManagedConfiguration {
}
I am looking to do the UnitTest for CMSConfig
I am not able to Mock or create the bean of CMSConfig as it's an interface. I have tried multiple approaches.
My UnitTest case file is
#ExtendWith(MockitoExtension.class)
public class MockitoServiceTest {
#Autowired
MockitoService mockitoService;
#ManagedConfiguration
private CMSConfig cmsConfig;
#BeforeAll
public static void before() {
System.setProperty("cms.configs.dir", Paths.get("src", "main", "resources").toFile().getAbsolutePath());
}
#Test
public void testCMS(){
assertEquals(cmsConfig.getDummy(),"dummyvalueUatRes");
}
}
Please help if there's any way to do this.
My mockitoService and cmsConfig are null while running the test case.

How to use byte-buddy in springboot

I want to use byte-buddy to intercept methods with java annotation. A simplified example is as follows:
Annotation
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#Documented
public #interface TraceLog {
String logName() default "";
}
The Interceptor class is
public class TraceLogInterceptor {
#RuntimeType
public static Object handleTraceLog(#Origin Method method,
#AllArguments Object[] args,
#SuperCall Callable<?> superCall) throws Exception {
TraceLog traceLogAnnotation = method.getAnnotation(TraceLog.class);
System.out.println(traceLogAnnotation.logName());
superCall.call();
}
}
The service class is
public class HelloServiceImpl {
#TraceLog(logName = "myLog")
public String writeHello(String name) {
return "Hello " + name;
}
}
The test method is
#Test
public void writeHello() throws IllegalAccessException, InstantiationException, IOException, NoSuchMethodException, InvocationTargetException {
DynamicType.Unloaded<?> dynamicType =
new ByteBuddy()
.subclass(HelloServiceImpl.class)
.method(ElementMatchers.isAnnotatedWith(TraceLog.class))
.intercept(MethodDelegation.to(TraceLogInterceptor.class))
.make();
HelloServiceImpl helloService = (HelloServiceImpl) dynamicType.load(this.getClass().getClassLoader())
.getLoaded()
.getConstructor()
.newInstance();
System.out.println(helloService.writeHello("XXXXX"));
}
It can work. However, I want to know how to inject the interceptor(TraceLogInterceptor) to spring. And I also want to know how to intercept all methods with the #TraceLog annotation and generate the corresponding proxy class without specifying the superclass(new ByteBuddy().subclass(xxx)). Thanks!

Mockito is not mocking out a member variable method return value

I have the following class that contains a member variable, but Mockito can't seem to mock the member variable's methods. Below is my System Under Test:
public class MessageConsumer {
private ConsumerResponse consumerResponse;
private NotificationConsumer notificationConsumer;
#Scheduled(cron = "${com.example.value}")
public void fetch() {
consumerResponse = notificationConsumer.fetchWithReturnConsumerResponse(); //no exception thrown on this line at all -- but could this be the cause of the problem in the test?
System.out.println("consumerResponse's responseCode: " + consumerResponse.getResponseCode()); // NullPointerException thrown here
}
public ConsumerResponse setConsumerResponse(ConsumerResponse consumerResponse) {
this.consumerResponse = consumerResponse;
}
public ConsumerResponse getConsumerResponse() {
return consumerResponse;
}
}
And the following is the relevant JUnit test for the class:
#SpringBootTest
#RunWith(MockitoJUnitRunner.class)
public class MessageConsumerTest {
#Mock
private ConsumerResponse consumerResponse;
#InjectMocks
private MessageConsumer messageConsumer;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
//Failing unit test
#Test
public void getResponseCodeShouldReturn200() {
Mockito.when(consumerResponse.getResponseCode()).thenReturn("200");
messageConsumer.fetch()
}
}
As you can see, I've mocked the ConsumerResponse consumerResponse variable to return "200" when the consumerResponse.getResponseCode() method gets invoked. Instead, I'm getting a NullPointerException.
I'm pretty sure I mocked the member variable correctly and initialized it appropriately (initMocks). I've spent days trying to figure this out. Where am I going wrong?
As NotificationConsumer is also an external dependency for this class, you have to also mock this class as otherwise consumerResponse = notificationConsumer.fetchWithReturnConsumerResponse(); will result into null within your test as you didn't mock the NotificationConsumer. In addition I would suggest not to use #SpringBootTest within this unit test as this annotation will boot the whole Spring context. The following snippet should help you:
#RunWith(MockitoJUnitRunner.class)
public class MessageConsumerTest {
#Mock
private ConsumerResponse consumerResponse;
#Mock
private NotificationConsumer notificationConsumer;
#InjectMocks
private MessageConsumer messageConsumer;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void getResponseCodeShouldReturn200() {
Mockito.when(notificationConsumer.fetchWithReturnConsumerResponse()).thenReturn(consumerResponse);
Mockito.when(consumerResponse.getResponseCode()).thenReturn("200");
messageConsumer.fetch();
}
}

Why Powermockito invokes my mocked method?

I want to mock private method, which called from my test method, but instead of mocking, PowerMockito invoke toMockMethod, and I get NPE.
toMockMethod is in the same class.
#RunWith(PowerMockRunner.class)
public class PaymentServiceImplTest {
private IPaymentService paymentService;
#Before
public void init() {
paymentService = PowerMockito.spy(Whitebox.newInstance
(PaymentServiceImpl.class));
MockitoAnnotations.initMocks(this);
}
#Test
public void test() throws Exception {
...
PowerMockito.doReturn(mockedReturn)
.when(paymentService,
"toMockMethod",
arg1, arg2);
}
}
Is it normal situation? What a sense to mock method if it has been invoked?
To enable static or non-public mocking with PowerMock for a class, the class should be added to annotation #PrepareForTest. In your case, it should be:
#RunWith(PowerMockRunner.class)
#PrepareForTest(PaymentServiceImpl.class)
public class PaymentServiceImplTest {
private IPaymentService paymentService;
#Before
public void init() {
paymentService = PowerMockito.spy(Whitebox.newInstance
(PaymentServiceImpl.class));
MockitoAnnotations.initMocks(this);
}
#Test
public void test() throws Exception {
...
PowerMockito.doReturn(mockedReturn)
.when(paymentService,
"toMockMethod",
arg1, arg2);
}
}
I'm gonna leave a second answer for my future self here. There's an alternative problem here. If you're calling Static.method make sure "method" is actually defined in Static and not up the hierarchy.
In my case the code called Static.method, but Static extends from StaticParent, and "method" is actually defined in StaticParent.
#RunWith(PowerMockRunner.class)
#PrepareForTest(StaticParent.class)
public class YourTestClass {
#Before
public init() {
PowerMockito.mockStatic(StaticParent.class);
when(StaticParent.method("")).thenReturn(yourReturnValue);
}
}
public class ClassYoureTesting {
public someMethod() {
Static.method(""); // This returns yourReturnValue
}

How to tell a Mockito Mock annotation to return a mock object which is not null?

I am trying to unit test a method, which has different branches depending upon the value of an object that is created inside it. The below code demonstrates it.
public class AClass {
public void method2() {
//Some code goes here
}
public void method1(BClass bObject) {
C_Class cObject = bObject.someMethodThatReturnsC();
if(cObject != null) {
method2();
method2();
}
}}
Below is the TestClass:
public class AClassTest {
#InjectMocks
AClass AClassSpy;
#Mock
BClass b_objectMock;
#Mock
C_Class c_objectMock;
#BeforeMethod
public void beforeMethod() {
AClassSpy = spy(new AClass());
MockitoAnnotations.initMocks(this);
}
public void method1Test () {
doReturn(c_objectMock).when(b_objectMock).someMethodThatReturnsC());
AClassSpy.method1(b_objectMock);
verify(AClassSpy, times(2).method2();
}
}
However, it always FAILS, since the c_objectMock is always null. What do I do to tell Mockito to not to return a null object?
It works good, just use #Before annotation from junit, not #BeforeMethod, and mark your test method like #Test and remove second bracket from
doReturn(c_objectMock).when(b_objectMock).someMethodThatReturnsC())<-this one;
and add bracket at verify:
verify(AClassSpy, times(2)<-here.method2();
And just take care of your code!
This should work:
public class AClassTest {
#InjectMocks
private AClass AClassSpy;
#Mock
private BClass b_objectMock;
#Mock
private C_Class c_objectMock;
#Before
public void beforeMethod() {
AClassSpy = spy(new AClass());
MockitoAnnotations.initMocks(this);
}
#Test
public void method1Test() {
doReturn(c_objectMock).when(b_objectMock).someMethodThatReturnsC();
AClassSpy.method1(b_objectMock);
verify(AClassSpy, times(2)).method2();
}
}
Instead of before method you can use annotation #RunWith. It looks clearly:
#RunWith(MockitoJUnitRunner.class)
public class AClassTest {
#Spy
#InjectMocks
private AClass AClassSpy;
#Mock
private BClass b_objectMock;
#Mock
private C_Class c_objectMock;
#Test
public void method1Test() {
doReturn(c_objectMock).when(b_objectMock).someMethodThatReturnsC();
AClassSpy.method1(b_objectMock);
verify(AClassSpy, times(2)).method2();
}
}
You are having this behaviour because you are not mocking property the call to someMethodThatReturnsC.
It should be:
doReturn(c_objectMock).when(b_objectMock).someMethodThatReturnsC();

Categories

Resources