Google app engine Google应用程序引擎(java)的集成测试

Google app engine Google应用程序引擎(java)的集成测试,google-app-engine,testing,integration-testing,Google App Engine,Testing,Integration Testing,我正在尝试为我的GAE/j应用程序开发一些有效的集成测试。我很熟悉——这些工具对于小型单元测试非常有用。我现在对开发测试实际web请求的集成测试感兴趣。例如,我想测试web.xml是否将servlet和过滤器映射到预期的URL,并测试我的JSP是否生成预期的URL 我的目标是在JVM中建立一个本地开发服务器,我可以对其发出请求。不过,我对其他整合策略持开放态度;如上所述,我只想有效地测试JSP生成和其他请求级功能 我已经设法使用DevAppServerFactory在同一JVM中启动了一个开发服

我正在尝试为我的GAE/j应用程序开发一些有效的集成测试。我很熟悉——这些工具对于小型单元测试非常有用。我现在对开发测试实际web请求的集成测试感兴趣。例如,我想测试web.xml是否将servlet和过滤器映射到预期的URL,并测试我的JSP是否生成预期的URL

我的目标是在JVM中建立一个本地开发服务器,我可以对其发出请求。不过,我对其他整合策略持开放态度;如上所述,我只想有效地测试JSP生成和其他请求级功能

我已经设法使用DevAppServerFactory在同一JVM中启动了一个开发服务器。但是,它生成的DevAppServer似乎使用了与主JVM不同的类加载器。这使得测试更具挑战性——我不能使用任何本地unittesting local*TestConfig类来控制此服务器的行为。类似地,我不能通过静态“滚动我自己的”钩子来修改行为,因为我可以在测试工具中变异的静态与DevAppServer看到的静态不同。这使得跳过与当前测试无关的功能(例如,需要登录)、注入失败、注入模拟等变得非常困难。这确实限制了我测试代码的完整性和效率


我发现web上与AppEngine集成测试的文档非常缺乏。我相信以前有人做过这件事……你有什么建议或资源可以分享吗?

基本上,你需要做两件事:

  • 添加两个servlet(或任何内容),,这只能在测试期间启用,允许您远程调用helper上的setup和teardown
  • 让servlet引擎以完全单线程的方式服务请求。这是必需的,因为出于某种原因,Google提供的助手类只在当前线程中生效

  • 我同意这一问题的记录不充分。
    我设法编写了一个端到端测试,将服务器作为黑盒启动并向其发送HTTP请求

    它的工作原理如下:

    package com.project.org;
    
    import static org.junit.Assert.assertEquals;
    import java.io.File;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.util.ArrayList;
    import java.util.List;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import com.google.appengine.api.urlfetch.HTTPResponse;
    import com.google.appengine.api.urlfetch.URLFetchServiceFactory;
    import com.google.appengine.tools.development.testing.BaseDevAppServerTestConfig;
    import com.google.appengine.tools.development.testing.DevAppServerTest;
    import com.google.appengine.tools.development.testing.DevAppServerTestRunner;
    import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
    
    @RunWith(DevAppServerTestRunner.class)
    @DevAppServerTest(HelloWorldTest.TestConfig.class)
    public class HelloWorldTest {
    
      public class TestConfig extends BaseDevAppServerTestConfig {
    
        @Override public File getSdkRoot() {
          // You may need to tweak this.
          return new File("../../appengine-java-sdk-1.9.15");
        }
    
        @Override public File getAppDir() {
          return new File("war");
        }
    
        @Override
        public List<URL> getClasspath() {
          // There may be an easier way to do this.
          List<URL> classPath = new ArrayList<>();
          try {
            String separator = System.getProperty("path.separator");
            String[] pathElements = System.getProperty("java.class.path").split(separator);
            for (String pathElement : pathElements) {
              classPath.add(new File(pathElement).toURI().toURL());
            }
          }
          catch (MalformedURLException e) {
            throw new RuntimeException(e);
          }
          return classPath;
        }
      }
    
      private final LocalServiceTestHelper testHelper;
      private final String port;
    
      public HelloWorldTest() {
        testHelper = new LocalServiceTestHelper();
        port = System.getProperty("appengine.devappserver.test.port");
      }
    
      @Before public void setUpServer() {
        testHelper.setUp();
      }
    
      @After public void tearDown() {
        testHelper.tearDown();
      }
    
      @Test public void testHelloWorld() throws Exception {
        URL url = new URL("http://localhost:" + port + "/hello");
        HTTPResponse response = URLFetchServiceFactory.getURLFetchService().fetch(url);
        assertEquals(200, response.getResponseCode());
        assertEquals("Hello world!", new String(response.getContent(), "UTF-8"));
      }
    }
    
    package com.project.org;
    导入静态org.junit.Assert.assertEquals;
    导入java.io.File;
    导入java.net.MalformedURLException;
    导入java.net.URL;
    导入java.util.ArrayList;
    导入java.util.List;
    导入org.junit.After;
    导入org.junit.Before;
    导入org.junit.Test;
    导入org.junit.runner.RunWith;
    导入com.google.appengine.api.urlfetch.HTTPResponse;
    导入com.google.appengine.api.urlfetch.URLFetchServiceFactory;
    导入com.google.appengine.tools.development.testing.BaseDevAppServerTestConfig;
    导入com.google.appengine.tools.development.testing.DevAppServerTest;
    导入com.google.appengine.tools.development.testing.DevAppServerTestRunner;
    导入com.google.appengine.tools.development.testing.LocalServiceTestHelper;
    @RunWith(DevAppServerTestRunner.class)
    @DevAppServerTest(HelloWorldTest.TestConfig.class)
    公共类HelloWorldTest{
    公共类TestConfig扩展了BaseDevAppServerTestConfig{
    @重写公共文件getSdkRoot(){
    //您可能需要对此进行调整。
    返回新文件(“../../appengine-java-sdk-1.9.15”);
    }
    @重写公共文件getAppDir(){
    返回新文件(“war”);
    }
    @凌驾
    公共列表getClasspath(){
    //也许有一种更简单的方法可以做到这一点。
    List classPath=new ArrayList();
    试一试{
    字符串分隔符=System.getProperty(“path.separator”);
    String[]pathElements=System.getProperty(“java.class.path”).split(分隔符);
    for(字符串pathElement:pathElements){
    添加(新文件(pathElement.toURI().toul());
    }
    }
    捕获(格式错误){
    抛出新的运行时异常(e);
    }
    返回类路径;
    }
    }
    私有最终LocalServiceTestHelper testHelper;
    专用最终字符串端口;
    公共HelloWorldTest(){
    testHelper=新的LocalServiceTestHelper();
    port=System.getProperty(“appengine.devappserver.test.port”);
    }
    @在public void setUpServer()之前{
    testHelper.setUp();
    }
    @公开作废后拆除(){
    testHelper.tearDown();
    }
    @Test public void testHelloWorld()引发异常{
    URL=新URL(“http://localhost:“+端口+”/hello”);
    HTTPResponse response=URLFetchServiceFactory.getURLFetchService().fetch(url);
    assertEquals(200,response.getResponseCode());
    assertEquals(“helloworld!”,新字符串(response.getContent(),“UTF-8”);
    }
    }
    

    现在我遇到的问题是,如果您有两个这样的测试,每个测试都单独通过,那么您不能在同一个二进制文件中运行它们。 get-Trown第37行的异常:

    IllegalStateException(“开发应用服务器已在运行。”)

    我不知道如何解决这个问题