2015-10-27 4 views
2

У меня есть метод, который принимает Play Http.Context и «делает некоторые вещи» с сеансом. Я хочу написать единичный тест только для этого метода. В частности, я хочу проверить, что если запрос приходит с некоторыми заголовками, мой метод работает правильно. Кажется, что самый простой способ сделать это надежно - создать FakeApplication и Controller для моего теста. Затем я буду использовать Helpers.fakeRequest, чтобы получить запрос, и Helpers.route, чтобы перенаправить этот запрос на мой контроллер. Контроллер будет вызывать мой метод, устанавливать некоторые переменные и т. Д., И тогда я мог бы утверждать успех и тому подобное.Play route/Controller только для модульного теста

Похоже на великолепный план, но я не могу понять, как добавить маршрут к моему контроллеру в FakeApplication. Обратите внимание, что этот контроллер не является частью моего приложения - это просто то, что я хочу использовать для этого теста. Поэтому я хочу определить его и построить только в одном модульном тесте; Я не хочу добавлять его в файл conf/routes.

В частности, я хочу что-то вроде этого:

// Maybe I can use GlobalSettings.onRouteRequest but the return type 
// is play.api.mvc.Handler which seems inaccessible from Java 
FakeApplication app = Helpers.fakeApplication(new MyGlobalSettings()); 
Http.Request request = Helpers.fakeRequest().withCookies(...).withBody(...); 
Controller testContoller = new MyTestController(); 
// This doesn't exist, but I want something like this 
app.addRoute("/foo", ctx -> testController.method(ctx)); 
running(app,() -> { 
    Helpers.route("/foo"); 
    assertThat(testContoller.itWorked()).isTrue(); 
} 

Я бегу Play 2.2.3 и писать на Java, а не Scala.

Я понимаю, что могу напрямую построить Http.Context и передать это моему методу. Однако это не мой предпочтительный подход по нескольким причинам:

  • Конструктор Http.Context принимает простой текст переменных сеанса. Я хочу проверить, что все работает правильно, когда запрос содержит зашифрованный файл cookie сеанса.
  • Конструктор Http.Context плохо документирован и кажется немного выключенным. Например, вы можете передать конструктору Http.Request, но вы также передаете данные cookie и данные сеанса. Итак, что происходит с данными cookie/сеанса по запросу? Соединяется ли с другими данными? Игнорируется?
  • Конструктор Http.Context сложно использовать из Java, поскольку для него требуется play.api.mvc.RequestHeader, который не может быть построен на Java, и play.mvc.Http.Request, который не может быть «полезен» из Java (вы можете его создать, но без файлов cookie , заголовки и т. д. и FakeRequest не могут быть преобразованы в Http.Request).
  • Он чувствует себя более «черным ящиком» для отправки запроса и обеспечения того, чтобы все работало, а не пыталось выяснить, как эта конкретная версия Play конвертирует мой запрос в Http.Context (например, ручное построение контекста, скорее всего, будет ломаться с новыми версии игры).

Любые идеи?

+0

какая версия игры! ты используешь? – w4tson

+0

Я запускаю Play 2.2.3 и записываю на Java, а не в Scala. –

ответ

1

Play Тесты в формате

running(fakeApplication(),() -> { 
    ... 
}); 

Хороши для тестирования приложения работает играть без HTTP слоя. Однако в вашем случае, если вы зависите от наличия контекста HTTP, поэтому я ваши варианты либо добавить в HTTP слое ...

running(testServer(3333), fakeApplication(),() -> { 
    WSResponse wsResponse = WS.url("http://localhost:3333/foo").setHeader("fizz", "buzz").get().get(30, TimeUnit.SECONDS); 
    .... 
    //assert some stuff 
}); 

или, может быть, попробовать использовать PowerMockito и издевается из вызова HTTP.Context. Как вы указываете, это более хрупкое, но позволит прагматично развернуть быстрый единичный тест.Что-то вроде

@RunWith(PowerMockRunner.class) 
public class FooTest { 

    @PrepareForTest({ Http.Context.class }) 
    @Test 
    public void test() { 
     mockStatic(Http.Context.class) 
     mockStatic(Http.class) 

     Http.Context mockContext = mock(Http.Context.class); 
     Map<String, String> args new HashMap<>(); 
     args.put("a","b"); 
     mockContext.args = args; 
     PowerMockito.when(Http.Context.current()).thenReturn(mockContext); 

     ClassUnderTest cut = new ClassUnderTest(); 
     cut.someMethod(); 
     //assertions 

    } 

} 
+0

спасибо за продуманный ответ. Я думаю, что первое решение, использующее тестовый сервер, имеет те же проблемы, что и в вопросе, а именно, что контроллер существует только в модульном тесте и не находится в моем «conf/routes», поэтому, насколько я знаю , вы не можете получить Play (через 'FakeApplication' или' TestServer') для направления на него запросов. Вторая версия работает, но есть недостатки, которые мы оба отметили. Вы знаете какой-либо способ заставить Play направлять запросы на «Контроллер», определенный в тесте? –

-1

Это как добавить дополнительный маршрут тест без изменения файла conf/routes. Но MyTestController.java нужно размещать в проекте/приложении вместо проекта/теста.

// app/controllers/TestController.java 
public static Result foo() { 
    return ok(); 
} 

// conf/test.routes 
GET  /foo   controllers.TestController.foo 

// test/controllers/TestTestController.java 
@Before 
Configuration config = new Configuration(ConfigFactory.parseFile(new File("conf/test.conf")).resolve()); 
Map<String, Object> configMap = config.asMap(); 
Map<String, Object> application = (Map<String, Object>) config.get("application"); 
application.put("router", "test.Routes"); 
configMap.put("application", application); 
fakeApplication(configMap); 

@Test 
FakeRequest fakeRequest = Helpers.fakeRequest("GET", "/foo"); 
Result result = Helpers.route(fakeRequest); 
assertThat(Helpers.status(result)).isEqualTo(200); 
+0

Хотя это теоретически может ответить на вопрос, [было бы предпочтительнее] (// meta.stackoverflow.com/q/8259) включить сюда основные части ответа и предоставить ссылку для справки. –

0
@Before 
public void startPlay() { 
    String conf = System.getProperty("config.file"); 
    if (conf == null) { 
     System.setProperty("config.file", "../../conf/test.conf"); 
    } 
    System.setProperty("play.http.router", "customer.Routes"); 
    super.startPlay(); 
} 
Смежные вопросы