如何为此方面编写 Junit Mockito 代码 class 以获得最大代码覆盖率
How to write the Junit Mockito code for this Aspect class for maximum code coverage
有人可以帮我为这段代码编写 Junit 并提供资源来学习它吗?我一直试图从多种资源中找出答案,但找不到任何东西。我需要模拟切入点和切入点中调用的方法。是否可以使用 Mockito
对此进行单元测试
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import com.sample.api.rest.account.AccountResource;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.CustomLog;
import lombok.extern.slf4j.slf4j;
@Aspect
@CustomLog
public class sample {
ObjectMapper mapper = new ObjectMapper();
long startTimeController = 0L;
long endTimeController = 0L;
@Pointcut("within(com.sample.api.rest.account. .) || "
+ "within(com.sample.api.rest.metadata..') ")
public void entryController() {}
@Pointcut("within(com. sample.api.rest.user..*)")
public void entryControllerUser() {}
@Pointcut("within(com.sample.api.service. .*)")
public void entryService() {}
@Pointcut("within(com. sample.cmo.repositories..*)")
public void entryDAO() {}
@Before("entryController()")
public void beforeOtherControllerCall(JoinPoint jp) throws JsonProcessingException {
String methodName = jp.getSignature().getName();
String className = jp.getTarget().getClass().toString();
Object[] arguments = jp.getArgs();
log.info(className + " Method : " + methodName + " Arguments passed : " +
mapper.writeValueAsString(arguments));
startTimeController = System.currentTimeMillis();
}
@Before("entryControllerUser()")
public void beforeUserControllerCall(JoinPoint jp) throws JsonProcessingException {
String methodName = jp.getSignature().getName();
String className = jp.getTarget().getClass().toString();
log.info(className + " Method : " + methodName);
startTimeController = System.currentTimeMillis();
}
@After("entryController() || entryControlleruser()")
public void afterControllerCall(JoinPoint jp) throws JsonProcessingException {
endTimeController = System.currentTimeMillis();
String methodName = jp.getSignature().getName();
String className = jp.getTarget().getClass().toString();
log.info(className + " Method : " + methodName + " Values returned :");
if (endTimeController != 0) {
log.info("Time consumed in " + className + " " + methodName + " call is "
+ (endTimeController - startTimeController) + "ms");
}
}
@Around("entryService()")
public Object executionTimeService(ProceedingJoinPoint pjp) throws Throwable {
String methodName = pjp.getSignature().getName();
String className = pjp.getTarget().getClass().toString();
Object[] arguments = pjp.getArgs();
log.info(className + " Method: " + methodName + " Arguments passed :" +
mapper.writeValueAsString(arguments));
long startTime = System.currentTimeMillis();
Object obj = pip.proceed();
long endTime = System.currentTimeMillis();
log.info(className + " Method : " + methodName + " Execution time: " + (endTime -
startTime) + "ms");
log.info(className + " Method : " + methodName + " Response received : " +
mapper.writeValueAsString(obj));
return obj;
}
@Around("entryDAO()")
public Object executionTimeDAO(ProceedingJoinPoint pjp ) throws Throwable {
String methodName pjp.getSignature().getName();
String className pjp.getTarget().getClass().toString();
Object[] arguments = pjp.getArgs();
log.info(className+" Method : "+methodName+" Arguments passed :"
+mapper.writeValueAsString(arguments) );
long startTime = System.currentTimeMillis();
Object obj = pip.proceed();
long endTime = System.currentTimeMillis();
log.info(className+" method : " + methodName+" Execution time: "
+(endTime-start Time)+"ms" );
log.info(className+" Method: "+methodName+" Response received : "+
mapper.writeValueAsString(obj));
return obj;
}
}
这是我尝试过的示例
@Test
public void testBeforeOtherControllerCall() throws Throwable{
JoinPoint joinPoint = mock(JoinPoint.class);
AspectLogging logging = mock(AspectLogging.class);
String[] args = {"arg1", "arg2"};
Object[] obj args)
Signature signature = mock (Signature.class);
when(joinPoint.getSignature().thenReturn(signature);
when(signature.getName().thenReturn("MethodName");
Object object = mock(Object.class);
when(joinPoint.getTarget().thenReturn(object);
when(object.getClass().thenReturn(objectClass);
when(joinPoint.getArgs().thenReturn(obj);
logging.beforeOtherControllerCali(joinPoint);
verify(joinPoint, times (1)).getSignature().getName().equals("MethodName");
}
前言
在尝试重现您的情况时,我不得不
猜猜你使用了哪些库和版本,
用定期创建的 SLF4J 记录器替换 Lombok 日志注释,因为正如 AspectJ 编译器在警告消息中告诉您的那样,Lombok 的字节码修改不适用于 AspectJ 编译器:java: You aren't using a compiler supported by lombok, so lombok will not work and has been disabled. (...) Lombok supports: sun/apple javac 1.6, ECJ
.当改用 Spring AOP 时,它可能适用于 Lombok,因为你只是在使用普通的 Java 编译器。然而,我在本机 AspectJ 中进行了测试。
修复方面中的许多语法错误并测试 Java 代码以及方面切入点中的几个语法错误。 classes 甚至没有编译,并且方面不能用错误的切入点做任何有意义的事情。如果您修改原始代码以创建独立示例,请在发布之前进行测试。在公开展示您的作品时,作为开发人员您应该多一点自豪感。这是你的免费机会,因为你是 SO 的新手,但下次我会关闭这个问题。
请务必阅读MCVE文章,尝试理解它并在以后提出更好的问题。
固定方面代码
package de.scrum_master.aspect;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Aspect
public class LoggingAspect {
private static final Logger log = LoggerFactory.getLogger(LoggingAspect.class);
ObjectMapper mapper = new ObjectMapper();
long startTimeController = 0L;
long endTimeController = 0L;
@Pointcut("within(com.sample.api.rest.account..*) || within(com.sample.api.rest.metadata..*)")
public void entryController() {}
@Pointcut("within(com.sample.api.rest.user..*)")
public void entryControllerUser() {}
@Pointcut("within(com.sample.api.service..*)")
public void entryService() {}
@Pointcut("within(com.sample.cmo.repositories..*)")
public void entryDAO() {}
@Before("entryController()")
public void beforeOtherControllerCall(JoinPoint jp) throws JsonProcessingException {
String methodName = jp.getSignature().getName();
String className = jp.getTarget().getClass().toString();
Object[] arguments = jp.getArgs();
log.info(className + " Method : " + methodName + " Arguments passed : " + mapper.writeValueAsString(arguments));
startTimeController = System.currentTimeMillis();
}
@Before("entryControllerUser()")
public void beforeUserControllerCall(JoinPoint jp) throws JsonProcessingException {
String methodName = jp.getSignature().getName();
String className = jp.getTarget().getClass().toString();
log.info(className + " Method : " + methodName);
startTimeController = System.currentTimeMillis();
}
@After("entryController() || entryControllerUser()")
public void afterControllerCall(JoinPoint jp) throws JsonProcessingException {
endTimeController = System.currentTimeMillis();
String methodName = jp.getSignature().getName();
String className = jp.getTarget().getClass().toString();
log.info(className + " Method : " + methodName + " Values returned :");
if (endTimeController != 0) {
log.info("Time consumed in " + className + " " + methodName + " call is " + (endTimeController - startTimeController) + "ms");
}
}
@Around("entryService()")
public Object executionTimeService(ProceedingJoinPoint pjp) throws Throwable {
String methodName = pjp.getSignature().getName();
String className = pjp.getTarget().getClass().toString();
Object[] arguments = pjp.getArgs();
log.info(className + " Method: " + methodName + " Arguments passed :" + mapper.writeValueAsString(arguments));
long startTime = System.currentTimeMillis();
Object obj = pjp.proceed();
long endTime = System.currentTimeMillis();
log.info(className + " Method : " + methodName + " Execution time: " + (endTime - startTime) + "ms");
log.info(className + " Method : " + methodName + " Response received : " + mapper.writeValueAsString(obj));
return obj;
}
@Around("entryDAO()")
public Object executionTimeDAO(ProceedingJoinPoint pjp) throws Throwable {
String methodName = pjp.getSignature().getName();
String className = pjp.getTarget().getClass().toString();
Object[] arguments = pjp.getArgs();
log.info(className + " Method : " + methodName + " Arguments passed :" + mapper.writeValueAsString(arguments));
long startTime = System.currentTimeMillis();
Object obj = pjp.proceed();
long endTime = System.currentTimeMillis();
log.info(className + " method : " + methodName + " Execution time: " + (endTime - startTime) + "ms");
log.info(className + " Method: " + methodName + " Response received : " + mapper.writeValueAsString(obj));
return obj;
}
}
固定测试
我之前在评论中给你发了两个链接,向你展示了如何编写单元测试和集成测试。你为什么不把它做得更像我的例子?你做错的一些事情是:
您为正在测试的 class 方面创建了一个模拟。为什么?你想要模拟依赖关系,而不是你真正想要测试的东西。就像在我的示例中一样,您应该正常实例化方面,仅在调用建议方法时注入模拟连接点。
您不能简单地验证相应的模拟对象链上的方法调用链,而是需要单独验证它们。所以,像 verify(joinPoint, times (1)).getSignature().getName().equals("MethodName")
这样的东西是行不通的。
您试图存根 when(object.getClass()).thenReturn(objectClass)
,这是不必要的,因为 Object.getClass()
returns 已经有东西了。此外,它是一个JDKbootstrapclass的最终方法。你不能简单地嘲笑它。
这个怎么样?
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.junit.Test;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class LoggingAspectTest {
@Test
public void testBeforeOtherControllerCall() throws Throwable {
JoinPoint joinPoint = mock(JoinPoint.class);
LoggingAspect logging = new LoggingAspect();
String[] args = { "arg1", "arg2" };
Object[] obj = args;
Signature signature = mock(Signature.class);
when(joinPoint.getSignature()).thenReturn(signature);
when(signature.getName()).thenReturn("MethodName");
Object object = mock(Object.class);
when(joinPoint.getTarget()).thenReturn(object);
when(joinPoint.getArgs()).thenReturn(obj);
logging.beforeOtherControllerCall(joinPoint);
verify(joinPoint, times(1)).getSignature();
verify(signature, times(1)).getName();
verify(joinPoint, times(1)).getTarget();
verify(joinPoint, times(1)).getArgs();
}
}
这涵盖了被测方法并验证了对您感兴趣的模拟对象的调用,尽管我发现这些验证有些问题。您真的要测试方面的内部结构吗?如果有的话,您应该测试副作用或结果。但是你当然可以像我的例子那样做。
我的 IDE 在 运行 覆盖测试时看起来像这样:
有人可以帮我为这段代码编写 Junit 并提供资源来学习它吗?我一直试图从多种资源中找出答案,但找不到任何东西。我需要模拟切入点和切入点中调用的方法。是否可以使用 Mockito
对此进行单元测试import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import com.sample.api.rest.account.AccountResource;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.CustomLog;
import lombok.extern.slf4j.slf4j;
@Aspect
@CustomLog
public class sample {
ObjectMapper mapper = new ObjectMapper();
long startTimeController = 0L;
long endTimeController = 0L;
@Pointcut("within(com.sample.api.rest.account. .) || "
+ "within(com.sample.api.rest.metadata..') ")
public void entryController() {}
@Pointcut("within(com. sample.api.rest.user..*)")
public void entryControllerUser() {}
@Pointcut("within(com.sample.api.service. .*)")
public void entryService() {}
@Pointcut("within(com. sample.cmo.repositories..*)")
public void entryDAO() {}
@Before("entryController()")
public void beforeOtherControllerCall(JoinPoint jp) throws JsonProcessingException {
String methodName = jp.getSignature().getName();
String className = jp.getTarget().getClass().toString();
Object[] arguments = jp.getArgs();
log.info(className + " Method : " + methodName + " Arguments passed : " +
mapper.writeValueAsString(arguments));
startTimeController = System.currentTimeMillis();
}
@Before("entryControllerUser()")
public void beforeUserControllerCall(JoinPoint jp) throws JsonProcessingException {
String methodName = jp.getSignature().getName();
String className = jp.getTarget().getClass().toString();
log.info(className + " Method : " + methodName);
startTimeController = System.currentTimeMillis();
}
@After("entryController() || entryControlleruser()")
public void afterControllerCall(JoinPoint jp) throws JsonProcessingException {
endTimeController = System.currentTimeMillis();
String methodName = jp.getSignature().getName();
String className = jp.getTarget().getClass().toString();
log.info(className + " Method : " + methodName + " Values returned :");
if (endTimeController != 0) {
log.info("Time consumed in " + className + " " + methodName + " call is "
+ (endTimeController - startTimeController) + "ms");
}
}
@Around("entryService()")
public Object executionTimeService(ProceedingJoinPoint pjp) throws Throwable {
String methodName = pjp.getSignature().getName();
String className = pjp.getTarget().getClass().toString();
Object[] arguments = pjp.getArgs();
log.info(className + " Method: " + methodName + " Arguments passed :" +
mapper.writeValueAsString(arguments));
long startTime = System.currentTimeMillis();
Object obj = pip.proceed();
long endTime = System.currentTimeMillis();
log.info(className + " Method : " + methodName + " Execution time: " + (endTime -
startTime) + "ms");
log.info(className + " Method : " + methodName + " Response received : " +
mapper.writeValueAsString(obj));
return obj;
}
@Around("entryDAO()")
public Object executionTimeDAO(ProceedingJoinPoint pjp ) throws Throwable {
String methodName pjp.getSignature().getName();
String className pjp.getTarget().getClass().toString();
Object[] arguments = pjp.getArgs();
log.info(className+" Method : "+methodName+" Arguments passed :"
+mapper.writeValueAsString(arguments) );
long startTime = System.currentTimeMillis();
Object obj = pip.proceed();
long endTime = System.currentTimeMillis();
log.info(className+" method : " + methodName+" Execution time: "
+(endTime-start Time)+"ms" );
log.info(className+" Method: "+methodName+" Response received : "+
mapper.writeValueAsString(obj));
return obj;
}
}
这是我尝试过的示例
@Test
public void testBeforeOtherControllerCall() throws Throwable{
JoinPoint joinPoint = mock(JoinPoint.class);
AspectLogging logging = mock(AspectLogging.class);
String[] args = {"arg1", "arg2"};
Object[] obj args)
Signature signature = mock (Signature.class);
when(joinPoint.getSignature().thenReturn(signature);
when(signature.getName().thenReturn("MethodName");
Object object = mock(Object.class);
when(joinPoint.getTarget().thenReturn(object);
when(object.getClass().thenReturn(objectClass);
when(joinPoint.getArgs().thenReturn(obj);
logging.beforeOtherControllerCali(joinPoint);
verify(joinPoint, times (1)).getSignature().getName().equals("MethodName");
}
前言
在尝试重现您的情况时,我不得不
猜猜你使用了哪些库和版本,
用定期创建的 SLF4J 记录器替换 Lombok 日志注释,因为正如 AspectJ 编译器在警告消息中告诉您的那样,Lombok 的字节码修改不适用于 AspectJ 编译器:
java: You aren't using a compiler supported by lombok, so lombok will not work and has been disabled. (...) Lombok supports: sun/apple javac 1.6, ECJ
.当改用 Spring AOP 时,它可能适用于 Lombok,因为你只是在使用普通的 Java 编译器。然而,我在本机 AspectJ 中进行了测试。修复方面中的许多语法错误并测试 Java 代码以及方面切入点中的几个语法错误。 classes 甚至没有编译,并且方面不能用错误的切入点做任何有意义的事情。如果您修改原始代码以创建独立示例,请在发布之前进行测试。在公开展示您的作品时,作为开发人员您应该多一点自豪感。这是你的免费机会,因为你是 SO 的新手,但下次我会关闭这个问题。
请务必阅读MCVE文章,尝试理解它并在以后提出更好的问题。
固定方面代码
package de.scrum_master.aspect;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Aspect
public class LoggingAspect {
private static final Logger log = LoggerFactory.getLogger(LoggingAspect.class);
ObjectMapper mapper = new ObjectMapper();
long startTimeController = 0L;
long endTimeController = 0L;
@Pointcut("within(com.sample.api.rest.account..*) || within(com.sample.api.rest.metadata..*)")
public void entryController() {}
@Pointcut("within(com.sample.api.rest.user..*)")
public void entryControllerUser() {}
@Pointcut("within(com.sample.api.service..*)")
public void entryService() {}
@Pointcut("within(com.sample.cmo.repositories..*)")
public void entryDAO() {}
@Before("entryController()")
public void beforeOtherControllerCall(JoinPoint jp) throws JsonProcessingException {
String methodName = jp.getSignature().getName();
String className = jp.getTarget().getClass().toString();
Object[] arguments = jp.getArgs();
log.info(className + " Method : " + methodName + " Arguments passed : " + mapper.writeValueAsString(arguments));
startTimeController = System.currentTimeMillis();
}
@Before("entryControllerUser()")
public void beforeUserControllerCall(JoinPoint jp) throws JsonProcessingException {
String methodName = jp.getSignature().getName();
String className = jp.getTarget().getClass().toString();
log.info(className + " Method : " + methodName);
startTimeController = System.currentTimeMillis();
}
@After("entryController() || entryControllerUser()")
public void afterControllerCall(JoinPoint jp) throws JsonProcessingException {
endTimeController = System.currentTimeMillis();
String methodName = jp.getSignature().getName();
String className = jp.getTarget().getClass().toString();
log.info(className + " Method : " + methodName + " Values returned :");
if (endTimeController != 0) {
log.info("Time consumed in " + className + " " + methodName + " call is " + (endTimeController - startTimeController) + "ms");
}
}
@Around("entryService()")
public Object executionTimeService(ProceedingJoinPoint pjp) throws Throwable {
String methodName = pjp.getSignature().getName();
String className = pjp.getTarget().getClass().toString();
Object[] arguments = pjp.getArgs();
log.info(className + " Method: " + methodName + " Arguments passed :" + mapper.writeValueAsString(arguments));
long startTime = System.currentTimeMillis();
Object obj = pjp.proceed();
long endTime = System.currentTimeMillis();
log.info(className + " Method : " + methodName + " Execution time: " + (endTime - startTime) + "ms");
log.info(className + " Method : " + methodName + " Response received : " + mapper.writeValueAsString(obj));
return obj;
}
@Around("entryDAO()")
public Object executionTimeDAO(ProceedingJoinPoint pjp) throws Throwable {
String methodName = pjp.getSignature().getName();
String className = pjp.getTarget().getClass().toString();
Object[] arguments = pjp.getArgs();
log.info(className + " Method : " + methodName + " Arguments passed :" + mapper.writeValueAsString(arguments));
long startTime = System.currentTimeMillis();
Object obj = pjp.proceed();
long endTime = System.currentTimeMillis();
log.info(className + " method : " + methodName + " Execution time: " + (endTime - startTime) + "ms");
log.info(className + " Method: " + methodName + " Response received : " + mapper.writeValueAsString(obj));
return obj;
}
}
固定测试
我之前在评论中给你发了两个链接,向你展示了如何编写单元测试和集成测试。你为什么不把它做得更像我的例子?你做错的一些事情是:
您为正在测试的 class 方面创建了一个模拟。为什么?你想要模拟依赖关系,而不是你真正想要测试的东西。就像在我的示例中一样,您应该正常实例化方面,仅在调用建议方法时注入模拟连接点。
您不能简单地验证相应的模拟对象链上的方法调用链,而是需要单独验证它们。所以,像
verify(joinPoint, times (1)).getSignature().getName().equals("MethodName")
这样的东西是行不通的。您试图存根
when(object.getClass()).thenReturn(objectClass)
,这是不必要的,因为Object.getClass()
returns 已经有东西了。此外,它是一个JDKbootstrapclass的最终方法。你不能简单地嘲笑它。
这个怎么样?
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.junit.Test;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class LoggingAspectTest {
@Test
public void testBeforeOtherControllerCall() throws Throwable {
JoinPoint joinPoint = mock(JoinPoint.class);
LoggingAspect logging = new LoggingAspect();
String[] args = { "arg1", "arg2" };
Object[] obj = args;
Signature signature = mock(Signature.class);
when(joinPoint.getSignature()).thenReturn(signature);
when(signature.getName()).thenReturn("MethodName");
Object object = mock(Object.class);
when(joinPoint.getTarget()).thenReturn(object);
when(joinPoint.getArgs()).thenReturn(obj);
logging.beforeOtherControllerCall(joinPoint);
verify(joinPoint, times(1)).getSignature();
verify(signature, times(1)).getName();
verify(joinPoint, times(1)).getTarget();
verify(joinPoint, times(1)).getArgs();
}
}
这涵盖了被测方法并验证了对您感兴趣的模拟对象的调用,尽管我发现这些验证有些问题。您真的要测试方面的内部结构吗?如果有的话,您应该测试副作用或结果。但是你当然可以像我的例子那样做。
我的 IDE 在 运行 覆盖测试时看起来像这样: