Java 用Mockito测试servlet API
我有Java 用Mockito测试servlet API,java,servlets,mockito,Java,Servlets,Mockito,我有AddBookController: public class BookAddController extends HttpServlet { @EJB(name = "BuyerServiceEJB") private BuyerServiceInterface buyerService; @EJB(name = "AuthorServiceEJB") private AuthorServiceInterface authorService;
AddBookController
:
public class BookAddController extends HttpServlet {
@EJB(name = "BuyerServiceEJB")
private BuyerServiceInterface buyerService;
@EJB(name = "AuthorServiceEJB")
private AuthorServiceInterface authorService;
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Book newBook = new Book();
newBook.setName(request.getParameter("name"));
newBook.setAuthor(authorService.findAuthorById(Long.parseLong(request.getParameter("author_id"))));
newBook.setBought(Boolean.parseBoolean(request.getParameter("sold")));
newBook.setGenre(request.getParameter("genre"));
newBook.setPrice(Integer.parseInt(request.getParameter("price")));
buyerService.addNewBook(newBook);
doGet(request, response);
}
我有一个测试班:
public class BookAddControllerTest {
final static Logger logger = Logger.getLogger(UserServiceBean.class);
private Book testBook = new Book();
private Author testAuthor = new Author();
@Before
public void precondition(){
logger.info("Add Book Controller Test");
testBook.setName("Возера Радасці");
testAuthor.setAuthor_id(1L);
testBook.setAuthor(testAuthor);
testBook.setBought(false);
testBook.setGenre("postmodernism");
testBook.setPrice(15);
}
@Test
public void testDoPost() {
logger.info("Test post request processing");
BookAddController bookAddController = Mockito.mock(BookAddController.class);
HttpServletRequest testRequest = Mockito.mock(HttpServletRequest.class);
HttpServletResponse testResponse = Mockito.mock(HttpServletResponse.class);
BuyerServiceInterface buyerServiceInterface = Mockito.mock(BuyerServiceInterface.class);
AuthorServiceInterface authorServiceInterface = Mockito.mock(AuthorServiceInterface.class);
when(testRequest.getParameter("name")).thenReturn("Возера Радасці");
when(testRequest.getParameter("author_id")).thenReturn("1");
when(testRequest.getParameter("sold")).thenReturn("false");
when(testRequest.getParameter("genre")).thenReturn("postmodernism");
when(testRequest.getParameter("price")).thenReturn("15");
bookAddController.doPost(testRequest, testResponse);
verify(buyerServiceInterface, times(1)).addNewBook(testBook);
verify(authorServiceInterface, times(1)).findAuthorById(Long.parseLong("1"));
verify(bookAddController, times(1)).doGet(testRequest, testResponse);
}
我收到例外情况:
java.lang.ClassFormatError: Absent Code attribute in method that is not native or abstract in class file javax/servlet/ServletException
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.privateGetMethodRecursive(Class.java:3048)
at java.lang.Class.getMethod0(Class.java:3018)
at java.lang.Class.getMethod(Class.java:1784)
at org.junit.internal.builders.SuiteMethodBuilder.hasSuiteMethod(SuiteMethodBuilder.java:18)
at org.junit.internal.builders.SuiteMethodBuilder.runnerForClass(SuiteMethodBuilder.java:10)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:26)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:33)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:98)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
问题:
doPost
方法正如user@SMA所暗示的那样,实际上您并没有测试任何东西,因为您只是在模拟代码上操作。您要做的是创建
BookAddController
的实例,并可能在调用doPost
时传入HttpServletRequest
和HttpServletResponse
的模拟实例。否则,您不会执行您所编写的任何代码,因此您无法知道您所编写的实际代码是否有效,或者是否发生了任何回归
至于例外情况,我怀疑可能是
junit
没有访问javaeeapi的权限。在pom中包含javaEE,它可能会起作用。更多信息,请看这里,因为user@SMA意味着您实际上没有测试任何东西,因为您只在模拟代码上操作。您要做的是创建BookAddController
的实例,并可能在调用doPost
时传入HttpServletRequest
和HttpServletResponse
的模拟实例。否则,您不会执行您所编写的任何代码,因此您无法知道您所编写的实际代码是否有效,或者是否发生了任何回归
至于例外情况,我怀疑可能是
junit
没有访问javaeeapi的权限。在pom中包含javaEE,它可能会起作用。这是一个令人兴奋的问题,因为Oracle没有为许多类提供方法体—您得到的只是API,这使得实际上无法使用JAR文件来运行任何东西。有关更多信息,请参见此:
这个问题可能是测试类路径上有javax:javieapi(或javax:javaeewebapi)库的结果。如果您有一个Maven项目,则POM文件中可能存在以下依赖项:
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>6.0</version>
</dependency>
爪哇
JavaEEAPI
6
或:
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>6.0</version>
</dependency>
爪哇
javaeewebapi
6
此依赖关系为您提供了JavaEEAPI,而不是实现。虽然此依赖项可用于编译,但不能用于执行代码(包括测试)
背景
当这些工件发布到Maven存储库时,Sun/Oracle从分类为“实现”的类中剥离了代码。因此,所有接口都是代码完整的,但任何抽象类或实现类中都没有代码。任何使用该类的尝试都可能失败
以下是关于Sun/Oracle为何这样做的论点摘录:
编译时,它们也希望运行。顺便说一句,我们一直在推广全套Java EE API,这些API只能用于编译——它们剥离了方法细节。这样,用户就不能在运行时使用这些工件
基本上,javax:javaeeAPI和javax:javaeeWebAPI Maven工件不是真正的东西——它们是“存根”。它们非常适合轻松地提供编译所需的依赖项,但当您需要做一些事情时,它们会完全中断
解决方法:不要使用javax.javaee-api或javax:javaee web api工件!相反,使用您需要的“真实”工件。不幸的是,没有Maven作用域可以从测试类路径中排除依赖项(尽管在surefire插件中有一个classpathDependencyExcludes配置选项,用于在测试期间将它们列入黑名单)
解决此问题的方法是使用以下方法:
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-servlet_3.0_spec</artifactId>
<version>1.0</version>
<scope>test</scope>
</dependency>
org.apache.geronimo.specs
geronimo-servlet_3.0_规范
1
测试
或者JBoss版本,或者其他一些版本,其中包含您正在使用的类的实际实现。这是一个令人兴奋的问题,因为Oracle没有为许多类提供方法体—您得到的只是API,这使得无法实际使用JAR文件来运行任何东西。有关更多信息,请参见此: 这个问题可能是测试类路径上有javax:javieapi(或javax:javaeewebapi)库的结果。如果您有一个Maven项目,则POM文件中可能存在以下依赖项:
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>6.0</version>
</dependency>
爪哇
JavaEEAPI
6
或:
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>6.0</version>
</dependency>
爪哇
javaeewebapi
6
此依赖关系为您提供了JavaEEAPI,而不是实现。虽然此依赖项可用于编译,但不能用于执行代码(包括测试)
背景
当这些工件发布到Maven存储库时,Sun/Oracle从分类为“实现”的类中剥离了代码。因此,所有接口都是代码完整的,但任何抽象类或实现类中都没有代码。任何使用该类的尝试都可能失败
以下是关于Sun/Oracle为何这样做的论点摘录:
编译时,它们也希望运行。顺便说一句,我们一直在推广全套Java EE API,这些API只能用于编译——它们剥离了方法细节。这样,用户就不能在运行时使用这些工件
基本上,javax:javaeeAPI和javax:javaeeWebAPI Maven工件不是真正的东西——它们是“存根”。它们非常适合轻松地提供编译所需的依赖项,但当您需要做一些事情时,它们会完全中断
解决方法:不要使用javax.javaee-api或javax:javaee web api工件!相反,使用您需要的“真实”工件。不幸的是,没有可以排除依赖项的Maven作用域