Приемочное тестирование предварительной загрузки данных в хранилище данных сервера разработки GAE

В моем приложении у меня есть набор DAO, которые я внедряю в свой прикладной уровень. Для приемочного теста, который я пишу, я хочу предварительно загрузить хранилище данных dev_server данными, поэтому я использую ту же конфигурацию Spring в своем тесте JUnit (используя аннотацию @ContextConfiguration), чтобы внедрить экземпляр соответствующего DAO в мой тест. Когда я на самом деле иду хранить некоторые данные, например:

dao.add(entity)

Я получаю ужасное сообщение «Для этого потока не зарегистрирована среда API».

Caused by: java.lang.NullPointerException: No API environment is registered for this thread.
 at com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppId(DatastoreApiHelper.java:108)
 at com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppIdNamespace(DatastoreApiHelper.java:118)
    ....

Вероятно, это связано с тем, что мой тестовый пример не прочитал в GAE application-web.xml сведения о приложении (хотя я предполагаю, что здесь я действительно мог ошибаться); поэтому он не знает, что нужно писать в то же хранилище данных, в которое читает/пишет приложение, работающее на dev_server.

Как я могу заставить свой тест «указывать» на то же хранилище данных, что и приложение? Есть ли какой-то механизм «источника данных», который я могу внедрить как в приложение, так и в тест? Есть ли способ заставить мой тест заставить API хранилища данных прочитать необходимую конфигурацию?


person kierans    schedule 22.01.2011    source источник


Ответы (3)


Здесь находится страница, на которой рассказывается о том, тесты, которые подключаются к хранилищу данных разработки. Это то, что вы ищете? В основном речь идет о двух классах, LocalServiceTestHelper и LocalDatastoreServiceTestConfig, которые можно использовать для настройки среды для тестирования. Хотя приведенный пример предназначен для модульных тестов, я считаю, что он также будет работать и в вашей ситуации.

Затем вы можете настроить такие параметры, как запись хранилища данных разработки на диск или просто хранение в памяти (для более быстрых тестов). Если вы хотите, чтобы эти данные находились в том же месте, что и ваш сервер разработки, вы, вероятно, захотите настроить это, так как я думаю, что по умолчанию используется опция «в памяти». Если вы посмотрите на javadoc есть метод "setBackingStoreLocation", с помощью которого вы можете указать на любой файл, который хотите.

person Peter Recore    schedule 22.01.2011
comment
Я попытался установить резервное хранилище хранилища данных (используя LocalDatastoreServiceTestConfig) в тесте, чтобы он был тем же файлом, в который записывает dev_server (например, WEB-INF/appengine-generated/local_db.bin), и тест успешно записывает объект в файл . Однако, когда я запускаю dev_server и смотрю на консоль администратора, объект, написанный в тесте, не появляется. Если я запускаю другой тест, который запрашивает хранилище данных (используя LocalDatastoreServiceTestConfig), сущность будет найдена. Сущность попадает в хранилище данных, но приложение, работающее на dev_server, не может ее увидеть. - person kierans; 24.01.2011
comment
Я думаю, что это как-то связано с пространствами имен, в которые dev_server и LocalServiceTestHelper помещают объекты, из-за чего приложение не видит тестовые объекты. Чтение code.google.com/appengine/docs/java/multitenancy/ Я попытался сделать так, чтобы тестовый код поместил объекты в пустое ('') пространство имен, которое делает приложение, но приложение по-прежнему не может их видеть. - person kierans; 29.01.2011
comment
Просто для ясности я использовал метод NamespaceManager.set() для изменения пространства имен как в коде dev_server, так и в тестовом коде. Я также пробовал с другой строкой, но это тоже не сработало. - person kierans; 29.01.2011
comment
Вот это да. это раздражает. хотя должен быть способ выполнить то, что вы хотите... нам нужен флаг для ник-кнопки на SO. - person Peter Recore; 30.01.2011

Я нашел решение!!!!

По какой-то причине поля Namespace, AppID и AuthDomain тестового хранилища данных должны соответствовать полям dev_server, тогда dev_server сможет видеть объекты, вставленные тестом.

Вы можете увидеть значения для среды (dev_server или тестовый код) со следующими операторами

System.out.println(NamespaceManager.get());
System.out.println(ApiProxy.getCurrentEnvironment().getAppId());
System.out.println(ApiProxy.getCurrentEnvironment().getAuthDomain());

В вашем экземпляре LocalServiceTestHelper (например, gaeHelper) вы можете установить значения для тестовой среды.

// the NamespaceManager is thread local.
NamespaceManager.set(NamespaceManager.getGoogleAppsNamespace());
gaeHelper.setEnvAppId(<the name of your app in appengine-web.xml>);
gaeHelper.setEnvAuthDomain("gmail.com");

Тогда dev_server увидит ваши сущности. Однако из-за проблем с синхронизацией, если тест записывает в хранилище данных после того, как dev_server был запущен, dev_server не увидит его, если только его нельзя принудительно перечитать файл (что я еще не понял). В противном случае сервер необходимо перезапустить.

person kierans    schedule 02.02.2011
comment
К сожалению, этот подход работает только с GAE ‹ 1.4.2 (я использовал 1.4.0). Что-то в API должно было измениться между версиями, которые сделали это решение недействительным. - person kierans; 17.07.2011

Я нашел обходной путь, хотя он не очень приятный, потому что каждый метод тестирования не очищает хранилище данных, как описано в статье Локальное модульное тестирование для Java, однако хранилище данных запускается чистым каждый раз, когда запускается класс Test, так что это не так уж плохо, если вы будете осторожны.

Проблема в том, что при использовании SpringJUnit4ClassRunner среда Spring создается до того, как можно будет запустить аннотацию @Before, решение заключается в использовании @BeforeClass и использовании статической переменной для LocalServiceTestHelper, чтобы они были созданы до настройки среды Spring.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:META-INF/spring/context-test.xml")
@Transactional
public class MyTest {


    @Inject
    private MyService myService;

    private static final LocalServiceTestHelper helper = 
        new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());

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

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

Если у кого-то есть лучшее решение, буду рад услышать!

person stivlo    schedule 26.08.2013