2015-03-13 2 views
1

У меня возникли трудности с написанием тестов для запросов БД для моего приложения, которое использует querydsl поверх mongo. Я нашел несколько примеров людей, которые просто тестируют сам объект запроса, но я хотел бы сделать еще один шаг и проверить, как выполняется запрос (например, тест интеграции), но без необходимости запуска всего процесса БД. То есть, издеваясь над DB исключительно с помощью java-инструментов.Mocking db query with querydsl - issue with Необязательно

Я ничего не мог найти для этого, такие инструменты, как DBUnit или DbSetup, нуждаются в фактическом подключении к БД. Поэтому я начал писать свои собственные классы, и это почти срабатывает. Идея заключается в использовании com.mysema.query.collections.CollQuery и mockito для имитации базы данных, которая будет получать запросы моего приложения, с оболочкой «CollQuery to Query». В принципе, он работает следующим образом:

public class MyServiceTest { 

    private MyService service; 
    private final Collection<MyObject> fakeTable = new ArrayList<>(); 

    @Before 
    public void setup() { 

     final Persister persister = mock(Persister.class); 
     when(persister.query(any(Class.class))) 
       // MockedQuery is the wrapper I wrote 
       .thenReturn(new MockedQuery<>(QMyObject.myObject, fakeTable)); 

     service = new MyService(persister); 
    } 

    @Test 
    public void shouldWork() { 
     fakeTable.add(new MyObject("one")); 
     fakeTable.add(new MyObject("two")); 
     fakeTable.add(new MyObject("three")); 

     final List<MyObject> result = service.getOne(); 
     // service.getOne would do something like: 
     // persister.query(QMyObject.myObject).where(QMyObject.myObject.name.eq("one")).list() 

     assertThat(result).hasSize(1); 
    } 
} 

... и в основном, похоже, что сработало! За исключением того, что мой код сильно использует опцию guava, и это, похоже, проблема для querydsl. Если вместо строки, MyObject принимает необязательный < String>, то я получаю ошибку:

com.mysema.codegen.CodegenException: Compilation of public class  Q_01363784216_1275614662_1275614662_1573163836_01698119955_566403833 { 

    public static Iterable<xxx.OpenedInterruption> eval(Iterable<xxx.OpenedInterruption> openedInterruption_, xxx.InterruptionType a1, xxx.InterruptionTargetType a2, com.google.common.base.Present a3) { 
     java.util.List<xxx.OpenedInterruption> rv = new java.util.ArrayList<xxx.OpenedInterruption>(); 
     for (xxx.OpenedInterruption openedInterruption : openedInterruption_) { 
      try { 
       if (com.mysema.query.collections.CollQueryFunctions.equals(com.mysema.query.collections.CollQueryFunctions.<xxx.InterruptionType>get(openedInterruption, "type"), a1) && com.mysema.query.collections.CollQueryFunctions.equals(com.mysema.query.collections.CollQueryFunctions.<xxx.InterruptionTargetType>get(openedInterruption, "targetType"), a2) && com.mysema.query.collections.CollQueryFunctions.equals(com.mysema.query.collections.CollQueryFunctions.<com.google.common.base.Optional>get(openedInterruption, "target"), a3)) { 
        rv.add(openedInterruption); 
       } 
      } catch (NullPointerException npe) { } 
     } 
     return rv; } 

} 

failed. 
     /Q_01363784216_1275614662_1275614662_1573163836_01698119955_566403833.java:3: error: Present is not public in com.google.common.base; cannot be accessed from outside package 
public static Iterable<xxx.OpenedInterruption> eval(Iterable<xxx.OpenedInterruption> openedInterruption_, xxx.InterruptionType a1, xxx.InterruptionTargetType a2, com.google.common.base.Present a3) { 
     ^
     1 error 

     at com.mysema.codegen.JDKEvaluatorFactory.compile(JDKEvaluatorFactory.java:74) 
     at com.mysema.codegen.AbstractEvaluatorFactory.createEvaluator(AbstractEvaluatorFactory.java:128) 
     at com.mysema.query.collections.DefaultEvaluatorFactory.createEvaluator(DefaultEvaluatorFactory.java:157) 
     at com.mysema.query.collections.DefaultQueryEngine.evaluateSingleSource(DefaultQueryEngine.java:176) 
     at com.mysema.query.collections.DefaultQueryEngine.list(DefaultQueryEngine.java:91) 
     at com.mysema.query.collections.AbstractCollQuery.list(AbstractCollQuery.java:219) 
     at xxx.BusinessInterruptionServiceImplTest$MockedQuery.list(BusinessInterruptionServiceImplTest.java:143) 
     at xxx.BusinessInterruptionServiceImplTest.setup(BusinessInterruptionServiceImplTest.java:79) 
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
     at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) 
     at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 
     at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) 
     at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24) 
     at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) 
     at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70) 
     at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) 
     at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) 
     at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) 
     at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) 
     at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) 
     at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) 
     at org.junit.runners.ParentRunner.run(ParentRunner.java:309) 
     at org.junit.runner.JUnitCore.run(JUnitCore.java:160) 
     at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74) 
     at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:211) 
     at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67) 
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
     at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134) 

Таким образом, это выглядит, как mysema пытается создать экземпляр com.google.common.base.Present, но не может для этого. Странная часть заключается в том, что тот же запрос отлично работает с моим производственным кодом, поэтому, возможно, проблема очень специфична для класса CollQuery, который я использую для издевательств.

Любая идея о том, как это решить?

Или, если кто-то может увидеть другой способ издеваться над БД, как я пытаюсь сделать, я был бы признателен за любую помощь!

Благодаря

PS: вот моя обертка "MockedQuery" класс (довольно просто):

public class MockedQuery<T> implements Query<T> { 

    private final Path<T> path; 
    private final CollQuery collQuery; 

    public MockedQuery(final Path<T> path, final Iterable<T> collection) { 
     this.path = path; 
     collQuery = from(path, collection); 
    } 

    @Override 
    public boolean exists() { 
     return collQuery.exists(); 
    } 

    @Override 
    public boolean notExists() { 
     return !exists(); 
    } 

    @Override 
    public CloseableIterator<T> iterate() { 
     return collQuery.iterate(path); 
    } 

    @Override 
    public List<T> list() { 
     return collQuery.list(path); 
    } 

    @Nullable 
    @Override 
    public T singleResult() { 
     return collQuery.singleResult(path); 
    } 

    @Nullable 
    @Override 
    public T uniqueResult() { 
     return collQuery.uniqueResult(path); 
    } 

    @Override 
    public SearchResults<T> listResults() { 
     return collQuery.listResults(path); 
    } 

    @Override 
    public long count() { 
     return collQuery.count(); 
    } 

    @Override 
    public Query<T> limit(final long limit) { 
     collQuery.limit(limit); 
     return this; 
    } 

    @Override 
    public Query<T> offset(final long offset) { 
     collQuery.offset(offset); 
     return this; 
    } 

    @Override 
    public Query<T> restrict(final QueryModifiers modifiers) { 
     collQuery.restrict(modifiers); 
     return this; 
    } 

    @Override 
    public Query<T> orderBy(final OrderSpecifier<?>... o) { 
     collQuery.orderBy(o); 
     return this; 
    } 

    @Override 
    public <U> Query<T> set(final ParamExpression<U> param, final U value) { 
     collQuery.set(param, value); 
     return this; 
    } 

    @Override 
    public Query<T> distinct() { 
     collQuery.distinct(); 
     return this; 
    } 

    @Override 
    public Query<T> where(final Predicate... o) { 
     collQuery.where(o); 
     return this; 
    } 
} 
+0

сгенерированный код менее полезен, чем код, который вы на самом деле проверяете здесь. Моя догадка заключается в том, что вы должны просто передать то, что ожидает объект, если только вы не ожидаете, что на этом уровне будет использоваться «Факультативный». – Makoto

+0

Моя модель данных заполнена опцией, которая управляется на более низком уровне своего рода адаптером «Модель для Монго» – Joel

+0

Для получения информации я открыл проблему в querydsl https://github.com/querydsl/querydsl/issues/1262 – Joel

ответ

0

Для получения дополнительной информации, она фиксируется в querydsl 3.6.3