gpt4 book ai didi

java - 如何修复 java.lang.IllegalStateException : You have not started an Objectify context

转载 作者:行者123 更新时间:2023-12-01 19:06:35 25 4
gpt4 key购买 nike

我正在尝试采用测试驱动开发方法来构建在 App Engine 上运行的基于 Java 的应用程序,但我在设置工作时遇到困难。

我的servlet

package mobi.grocerymonkey.groceryapp;

import com.google.appengine.api.utils.SystemProperty;

import java.io.IOException;
import java.io.BufferedReader;
import java.util.Properties;

import org.json.JSONObject;
import java.util.logging.Logger;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;

import static com.googlecode.objectify.ObjectifyService.ofy;
import com.googlecode.objectify.ObjectifyService;

/* This is the servlet */
@WebServlet(name = "GroceryServlet", value = "/grocery")
public class GroceryServlet extends HttpServlet {

private static final Logger log = Logger.getLogger(GroceryServlet.class.getName());

@Override
public void init() throws ServletException {
log.info("context init");
ObjectifyService.init();
ObjectifyService.register(Grocery.class);
}

@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException {

response.setContentType("text/plain");
response.getWriter().println("Hello Kitty");
}

@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException {
BufferedReader reader = request.getReader();
String line = null;
StringBuffer stringBuffer = new StringBuffer();
while((line = reader.readLine()) != null) {
stringBuffer.append(line);
}
String jsonString = stringBuffer.toString();
JSONObject json = new JSONObject(jsonString);
log.info("JSON "+ jsonString);

Grocery grocery = new Grocery();
grocery.setName((String) json.get("name"));
grocery.setQuantity((Integer) json.get("quantity"));

ofy().save().entity(grocery).now();

log.info("JSON name "+ grocery.getName());

response.setContentType("application/json");
response.getWriter().println(jsonString);
}

}

web.xml 文件

<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<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>
</web-app>

我的单元测试

package mobi.grocerymonkey.groceryapp;

import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.mock;

import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.cloud.datastore.DatastoreOptions;

import com.google.cloud.datastore.DatastoreOptions;
import com.googlecode.objectify.ObjectifyFactory;
import com.googlecode.objectify.ObjectifyService;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.json.JSONObject;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.BufferedReader;
import java.io.StringReader;
import java.io.Reader;
import java.io.Closeable;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* Unit tests for {@link HelloAppEngine}.
*/
@RunWith(JUnit4.class)
public class GroceryServletTest {
private static final String MOCK_URL = "/grocery";
// Set up a helper so that the ApiProxy returns a valid environment for local testing.
private final LocalServiceTestHelper helper =
new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());
private Closeable closeable;

@Mock
private HttpServletRequest mockRequest;

@Mock
private HttpServletResponse mockResponse;

private StringWriter responseWriter;
private GroceryServlet servletUnderTest;

@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
helper.setUp();

ObjectifyService.init(new ObjectifyFactory(
DatastoreOptions.newBuilder()
.setHost("http://localhost:8081")
.setProjectId("enduring-trees-259812")
.build()
.getService()
));
closeable = ObjectifyService.begin();

// Set up some fake HTTP requests
when(mockRequest.getRequestURI()).thenReturn(MOCK_URL);

JSONObject grocery = new JSONObject();
grocery.put("name", "Beer");

Reader inputString = new StringReader(grocery.toString());
BufferedReader reader = new BufferedReader(inputString);
when(mockRequest.getReader()).thenReturn(reader);

// Set up a fake HTTP response.
responseWriter = new StringWriter();
when(mockResponse.getWriter()).thenReturn(new PrintWriter(responseWriter));

servletUnderTest = new GroceryServlet();
servletUnderTest.init();
}

@After public void tearDown() throws Exception {
closeable.close();
helper.tearDown();
}

@Test
public void doGetWritesResponse() throws Exception {
servletUnderTest.doGet(mockRequest, mockResponse);

// We expect our hello world response.
assertThat(responseWriter.toString())
.contains("Hello Kitty");
}

@Test
public void doPostWritesResponse() throws Exception {
JSONObject reqObj = new JSONObject();
reqObj.put("name", "Beer");
reqObj.put("quantity", 5);
StringReader reader = new StringReader(reqObj.toString());

when(mockRequest.getReader()).thenReturn(new BufferedReader(new StringReader(reqObj.toString())));

servletUnderTest.doPost(mockRequest, mockResponse);

// We expect our hello world response.
assertThat(responseWriter.toString())
.contains(reqObj.getString("name"));
}
}

测试失败并显示以下错误消息

[ERROR] Tests run: 2, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.103 s <<< FAILURE! - in mobi.grocerymonkey.groceryapp.GroceryServletTest [ERROR] doPostWritesResponse(mobi.grocerymonkey.groceryapp.GroceryServletTest) Time elapsed: 0.078 s <<< ERROR! 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 mobi.grocerymonkey.groceryapp.GroceryServletTest.doPostWritesResponse(GroceryServletTest.java:109)

这是由我的 servlet 中的 y().save().entity(grocery).now() 行引起的。当我删除它时,测试运行没有错误。

我尝试采用不同的方法来解决在 stackoverflow 上发现的此错误,但没有成功。

应该如何设置测试/应用程序才能使用测试驱动方法进行开发?我正在寻找一种能够首先编写单元测试然后编写实际应用程序的方法。但如何才能成功呢?

(免责声明,我已经有十多年没有使用 Java 了)

更新

ServletContext 文件

package mobi.grocerymonkey.groceryapp;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

import java.io.Closeable;
import java.io.IOException;

import com.googlecode.objectify.ObjectifyService;
import static com.googlecode.objectify.ObjectifyService.ofy;

@WebListener
public class GroceryContextListener implements ServletContextListener {

private ServletContext context;
private Closeable closeable;

public void contextInitialized(ServletContextEvent event) {
this.context = event.getServletContext();

ObjectifyService.init();
this.closeable = ObjectifyService.begin();
ObjectifyService.register(Grocery.class);
System.out.println("Context initialized");
}

public void contextDestroyed(ServletContextEvent event) {
try {
this.closeable.close();
} catch(IOException ioe) {

}
}
}

单元测试文件

package mobi.grocerymonkey.groceryapp;

import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.mock;

import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.cloud.datastore.DatastoreOptions;

import com.google.cloud.datastore.DatastoreOptions;
import com.googlecode.objectify.ObjectifyFactory;
import com.googlecode.objectify.ObjectifyService;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.json.JSONObject;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.BufferedReader;
import java.io.StringReader;
import java.io.Reader;
import java.io.Closeable;
import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletContextEvent;

/**
* Unit tests for {@link HelloAppEngine}.
*/
@RunWith(JUnit4.class)
public class GroceryServletTest {
private static final String MOCK_URL = "/grocery";
// Set up a helper so that the ApiProxy returns a valid environment for local testing.
private final LocalServiceTestHelper helper =
new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());
private Closeable closeable;

@Mock
private HttpServletRequest mockRequest;

@Mock
private HttpServletResponse mockResponse;

private ServletContextListener contextListener;
private ServletContext context;

private StringWriter responseWriter;
private GroceryServlet servletUnderTest;

@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
helper.setUp();

contextListener = new GroceryContextListener();
context = mock(ServletContext.class);

// Set up some fake HTTP requests
when(mockRequest.getRequestURI()).thenReturn(MOCK_URL);

JSONObject grocery = new JSONObject();
grocery.put("name", "Beer");

Reader inputString = new StringReader(grocery.toString());
BufferedReader reader = new BufferedReader(inputString);
when(mockRequest.getReader()).thenReturn(reader);

// when(mockRequest.getServletContext()).thenReturn(context);

// Set up a fake HTTP response.
responseWriter = new StringWriter();
when(mockResponse.getWriter()).thenReturn(new PrintWriter(responseWriter));

servletUnderTest = new GroceryServlet();
}

@After
public void tearDown() throws Exception {
helper.tearDown();
}

@Test
public void doGetWritesResponse() throws Exception {
servletUnderTest.doGet(mockRequest, mockResponse);

// We expect our hello world response.
assertThat(responseWriter.toString())
.contains("Hello Kitty");
}

@Test
public void doPostWritesResponse() throws Exception {
contextListener.contextInitialized(new ServletContextEvent(context));

JSONObject reqObj = new JSONObject();
reqObj.put("name", "Beer");
reqObj.put("quantity", 5);
StringReader reader = new StringReader(reqObj.toString());

when(mockRequest.getReader()).thenReturn(new BufferedReader(new StringReader(reqObj.toString())));

servletUnderTest.doPost(mockRequest, mockResponse);

// We expect our hello world response.
assertThat(responseWriter.toString())
.contains(reqObj.getString("name"));
}
}

Servlet 文件

package mobi.grocerymonkey.groceryapp;

import com.google.appengine.api.utils.SystemProperty;

import java.io.IOException;
import java.io.BufferedReader;
import java.util.Properties;

import org.json.JSONObject;
import java.util.logging.Logger;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;

import static com.googlecode.objectify.ObjectifyService.ofy;
import com.googlecode.objectify.ObjectifyService;

/* This is the servlet */
@WebServlet(name = "GroceryServlet", value = "/grocery")
public class GroceryServlet extends HttpServlet {

private static final Logger log = Logger.getLogger(GroceryServlet.class.getName());

@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException {

response.setContentType("text/plain");
response.getWriter().println("Hello Kitty");
}

@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException {
BufferedReader reader = request.getReader();
String line = null;
StringBuffer stringBuffer = new StringBuffer();
while((line = reader.readLine()) != null) {
stringBuffer.append(line);
}
String jsonString = stringBuffer.toString();
JSONObject json = new JSONObject(jsonString);
log.info("JSON "+ jsonString);

Grocery grocery = new Grocery();
grocery.setName((String) json.get("name"));
grocery.setQuantity((Integer) json.get("quantity"));

ofy().save().entity(grocery).now();

log.info("JSON name "+ grocery.getName());

response.setContentType("application/json");
response.getWriter().println(jsonString);
}

}

现在,我在运行测试时收到“com.google.cloud.datastore.DatastoreException:未经身份验证”错误,所以看起来我的方向是正确的。我是否会将数据存储凭据存储在 web.xml 中,然后将它们传递到类似于

的上下文
ObjectifyService.init(new ObjectifyFactory(
DatastoreOptions.newBuilder()
.setHost("http://localhost:8081")
.setProjectId("enduring-trees-259812")
.build()
.getService()
));
ObjectifyService.factory().register(Grocery.class);

新更新

我升级到Junit5并将整个测试重写为这个

package mobi.grocerymonkey.groceryapp;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.AfterAll;
import static org.junit.jupiter.api.Assertions.assertEquals;

import com.googlecode.objectify.ObjectifyFactory;
import com.googlecode.objectify.ObjectifyService;
import com.googlecode.objectify.util.Closeable;
import static com.googlecode.objectify.ObjectifyService.factory;
import static com.googlecode.objectify.ObjectifyService.ofy;
import com.googlecode.objectify.Key;

import com.google.cloud.datastore.Datastore;
import com.google.cloud.datastore.DatastoreOptions;
import com.google.cloud.datastore.testing.LocalDatastoreHelper;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;

import mobi.grocerymonkey.groceryapp.util.TestBase;

import mobi.grocerymonkey.groceryapp.domain.Grocery;
import mobi.grocerymonkey.groceryapp.domain.GroceryList;

public class MyFirstTest extends TestBase {

// Maximum eventual consistency.
private final static LocalServiceTestHelper helper =
new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig()
.setDefaultHighRepJobPolicyUnappliedJobPercentage(100));

Closeable closeable;

@BeforeAll
public static void setUp() {
helper.setUp();
}

@AfterAll
public static void tearDown() {
helper.tearDown();
}

@BeforeEach
public void setUpEach() {
ObjectifyService.init(new ObjectifyFactory(
DatastoreOptions.getDefaultInstance().getService()));
closeable = ObjectifyService.begin();
}

@AfterEach
public void tearDownEach() {
closeable.close();
}

@DisplayName("Test MyFirstTest.testAddition()")
@Test
public void testAddition() {
assertEquals(1 + 1, 2);
}

@DisplayName("Testing testGroceryList()")
@Test
public void testGroceryList() {
factory().register(GroceryList.class);

GroceryList list = new GroceryList("Weekend Beer List");
Key<GroceryList> k1 = ofy().save().entity(list).now();

assertEquals(1+1, 2);
}
}

现在特意将其保存在一个文件中。但由于某种原因,数据存储无法找到运行测试时正在运行的模拟器。我收到数据存储未验证错误。

在运行单元测试之前,我运行了 gcloud beta emulators datastore start$(gcloud beta emulators datastore env-init)

最佳答案

问题是您调用了 ObjectifyService.init() 两次,但只在第一个(废弃的)工厂上调用了 begin()

您在 setUp() 方法中调用 init(),该方法初始化静态 ObjectifyFactory。然后,您可以使用 ObjectifyService.begin() 调用在该工厂上打开一个 session 。

setUp() 的末尾,您调用 servletUnderTest.init(),它还会调用 ObjectifyService.init()。这取代了静态ObjectifyFactory。当您下次执行 servlet 并调用 ofy()... 时,您使用的工厂尚未启动 session 。

看一下 ObjectifyService 的代码。从字面上看,只需几行代码即可包装静态 ObjectifyFactory 实例。

如果您有多个 servlet,则此代码在生产环境中也无法正常工作 - 您只想初始化并注册您的类一次。我建议使用 ServletContextListener 来执行此操作。

关于java - 如何修复 java.lang.IllegalStateException : You have not started an Objectify context,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59542836/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com