如何解决"你还没有开始客观化背景"在JUnit?

时间:2014-12-31 22:40:46

标签: google-app-engine google-cloud-datastore objectify

我在JUnit中运行了一些Objectify测试代码,我收到了这个错误:

java.lang.IllegalStateException: You have not started an Objectify context. You are probably missing the ObjectifyFilter. If you are not running in the context of an http request, see the ObjectifyService.run() method.
    at com.googlecode.objectify.ObjectifyService.ofy(ObjectifyService.java:44)
    at com.googlecode.objectify.impl.ref.LiveRef.<init>(LiveRef.java:31)
    at com.googlecode.objectify.Ref.create(Ref.java:26)
    at com.googlecode.objectify.Ref.create(Ref.java:32)
    at com.netbase.followerdownloader.repository.DownloadTaskRepositoryImpl.create(DownloadTaskRepositoryImpl.java:35)
    at com.netbase.followerdownloader.repository.DownloadTaskRepositoryImplTest.setUp(DownloadTaskRepositoryImplTest.java:45)

如何为测试代码解决此问题?

5 个答案:

答案 0 :(得分:11)

Jeff Schnitzer在这里回答:https://groups.google.com/forum/#!topic/objectify-appengine/8HinahG7irg。该链接指向https://groups.google.com/forum/#!topic/objectify-appengine/O4FHC_i7EGk,其中Jeff建议以下快速而肮脏的解决方法:

  • 我的@BeforeMethod开始客观化上下文(ObjectifyService.begin())

  • 我的@AfterMethod关闭了客观化背景

杰夫建议我们改用ObjectifyService.run(),但承认这项工作更多。

以下是我的实施方式:

public class DownloadTaskRepositoryImplTest {
    // maximum eventual consistency (see https://cloud.google.com/appengine/docs/java/tools/localunittesting)
    private final LocalServiceTestHelper helper =
        new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig()
            .setDefaultHighRepJobPolicyUnappliedJobPercentage(100));

    private Closeable closeable;

    @Before
    public void setUp() {
        helper.setUp();
        ObjectifyRegistrar.registerDataModel();
        closeable = ObjectifyService.begin();
    }

    @After
    public void tearDown() {
        closeable.close();

        helper.tearDown();
    }

答案 1 :(得分:8)

我也有这个问题,并注意到我没有将ObjectifyFilter添加到我的web.xml

<filter>
    <filter-name>ObjectifyFilter</filter-name>
    <filter-class>com.googlecode.objectify.ObjectifyFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>ObjectifyFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

我还必须在我的WEB-INF&gt; lib目录中包含Objectify和guava jar,并将它们包含在我的构建路径中。

答案 2 :(得分:1)

我遇到了同样的错误,this solusion为我工作

  

我有一个基于端点的应用程序使用Objectify。当我保留默认/自动缩放时,一切都很好。但是,一旦启用基本缩放,我在执行端点方法时会遇到以下异常:

[INFO] java.lang.IllegalStateException: You have not started an Objectify context. You are probably missing the ObjectifyFilter. If you are not running in the context of an http request, see the ObjectifyService.run() method.
[INFO]  at com.googlecode.objectify.ObjectifyService.ofy(ObjectifyService.java:44)
[INFO]  at com.myco.myapp.dao.datastore.OfyService.ofy(OfyService.java:62)
  

好消息是,当您启用RequestDispatcher时,这会消失   支持web.xml文件就像这样。我认为这是一份文件   问题,然后,但我不知道如果我编辑了,是否所有人都会同意   维基页面直接。这是建议的web.xml条目,它起作用   对我来说:

   <filter>
    <filter-name>ObjectifyFilter</filter-name>
    <filter-class>com.googlecode.objectify.ObjectifyFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>ObjectifyFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>

答案 3 :(得分:0)

改进michael-osofsky的答案,我把它添加到我的帮助类

public static void registerDataModel() {
    try {
        factory().register(Profile.class);
    } catch (Exception e){
        e.printStackTrace();
    }
}

并重新加入

ObjectifyRegistrar.registerDataModel();

这个

OfyService.registerDataModel();

<强> OfyService.java

public static void registerDataModel() {
    try {
        factory().register(Profile.class);
    } catch (Exception e){
        e.printStackTrace();
    }
}

答案 4 :(得分:0)

由迈克尔·奥索夫斯基(Michael Osofsky)提供的链接中的Jeff Schnitzer says

  

在测试中,您应该对“请求”有一些概念,即使它只是概念上的。如果“每个测试本身就是一个请求”,则可以将@ Before / @ After与ObjectifyService.begin()结合使用来划分请求。但是,这实际上可能不是您的测试的工作方式,而是我的测试的工作方式。

他接着说:

  

使用JDK8闭包会更漂亮,但是这个想法很简单-您在表示请求的上下文中包装了一些工作单元。在该包装中添加更多身份验证之类的上下文可能也很聪明。

我想出了他的想法的以下实现。使用下面的解决方案,您可以确保对servlet处理程序的每次调用都获得一个新的Objectify会话,同时仍在一行代码中进行servlet处理程序的调用。它还使您的测试从显着担心Objectify的工作中解脱出来,并允许您在Servlet处理程序周围添加其他非Objectify上下文。

我下面的解决方案适用于Objectify 5.1.22。我尝试使用Objectify 6+,但是遇到了与this有关的问题。

首先,定义一个自定义的Supplier,它可以捕获Servlet处理程序引发的异常。

  @FunctionalInterface
  public interface ServletSupplier<T> {

  T get()
    throws ServletException, IOException;
  }

接下来,定义一个接受您的新自定义供应商作为输入的包装器方法,并将对ServletSupplier.get()的调用包装在调用ObjectifyService.begin()的try-with-resources块中。您还必须在调用ServletSupplier.get()之前注册您的实体类。

  public <T> T runInServletContext(ServletSupplier<T> servletMethod)
      throws ServletException, IOException {

    try (Closeable session = ObjectifyService.begin()) {
      ObjectifyService.register(MyObj.class);
      return servletMethod.get();
    }
  }

最后,在测试中调用servlet处理程序的任何地方,都应该使用wrapper方法进行操作。

  MyObj myObjPost = runInServletContext(() -> getServlet().doPost(request, response));
  // Assert results of doPost call.
  MyObj myObjGet = runInServletContext(() -> getServlet().doGet(request, response));
  // Assert results of doGet call.