/** * Copyright (C) 2013 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.doctester; import org.apache.http.cookie.Cookie; import org.doctester.rendermachine.RenderMachine; import org.doctester.rendermachine.RenderMachineCommands; import org.doctester.rendermachine.RenderMachineImpl; import org.doctester.testbrowser.*; import org.hamcrest.Matcher; import org.junit.AfterClass; import org.junit.Before; import org.junit.Rule; import org.junit.rules.TestRule; import org.junit.rules.TestWatcher; import org.junit.runner.Description; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; public abstract class DocTester implements TestBrowser, RenderMachineCommands { @Rule public TestRule testWatcher = new TestWatcher() { @Override protected void starting(Description description) { classNameForDocTesterOutputFile = description.getClassName(); } }; /** * classNameForDocTesterOutputFile will be set by the testWatcher. That way * we can easily generate a filename as output filename. Usually it is * something like "com.mycompany.NameOfClassTest". */ private String classNameForDocTesterOutputFile; private final Logger logger = LoggerFactory.getLogger(DocTester.class); // Unique for each test method. private TestBrowser testBrowser; // Unique for whole testClass => one outputfile per testClass. // Protected only for testing protected static RenderMachine renderMachine = null; @Before public void setupForTestCaseMethod() { initRenderingMachineIfNull(); // Set a fresh TestBrowser for each testmethod. testBrowser = getTestBrowser(); renderMachine.setTestBrowser(testBrowser); // This is all a bit strange. But JUnit's @BeforeClass // is static. Therefore the only possibility to transmit // the filename to the renderMachine is here. // We accept that we set the fileName too often. renderMachine.setFileName(classNameForDocTesterOutputFile); } public void initRenderingMachineIfNull() { if (renderMachine == null) { renderMachine = getRenderMachine(); } } @AfterClass public static void finishDocTest() { if (renderMachine != null) { renderMachine.finishAndWriteOut(); renderMachine = null; } } // //////////////////////////////////////////////////////////////////////// // Say methods to print stuff into html // //////////////////////////////////////////////////////////////////////// @Override public final void say(String textAsParagraph) { renderMachine.say(textAsParagraph); } @Override public final void sayNextSection(String textAsH1) { renderMachine.sayNextSection(textAsH1); } @Override public final void sayRaw(String rawHtml) { renderMachine.sayRaw(rawHtml); } @Override public final <T> void sayAndAssertThat(String message, String reason, T actual, Matcher<? super T> matcher) { renderMachine.sayAndAssertThat(message, reason, actual, matcher); } @Override public final <T> void sayAndAssertThat(String message, T actual, Matcher<? super T> matcher) { sayAndAssertThat(message, "", actual, matcher); } // ////////////////////////////////////////////////////////////////////////// // Inlined methods of the TestBrowser (for convenience) // ////////////////////////////////////////////////////////////////////////// /** * @return all cookies saved by this TestBrowser. */ @Override public final List<Cookie> getCookies() { return testBrowser.getCookies(); } @Override public final List<Cookie> sayAndGetCookies() { return testBrowser.getCookies(); } @Override public final Cookie getCookieWithName(String name) { return testBrowser.getCookieWithName(name); } @Override public final Cookie sayAndGetCookieWithName(String name) { return testBrowser.getCookieWithName(name); } @Override public final void clearCookies() { testBrowser.clearCookies(); } @Override public final Response makeRequest(Request httpRequest) { return testBrowser.makeRequest(httpRequest); } @Override public final Response sayAndMakeRequest(Request httpRequest) { return renderMachine.sayAndMakeRequest(httpRequest); } // ////////////////////////////////////////////////////////////////////////// // Configuration of DoctestJ // ////////////////////////////////////////////////////////////////////////// /** * You may override this method if you want to supply your own testbrowser * for your class or classes. * * @return a TestBrowser that will be used for each test method. */ public TestBrowser getTestBrowser() { return new TestBrowserImpl(); } /** * You may override this method if you want to supply your own rendering * machine for your class or classes. * * @return a RenderMachine that generates output and lives for a whole test * class. */ public RenderMachine getRenderMachine() { return new RenderMachineImpl(); } /** * Convenience method that allows you to write tests with the testbrowser in * a fluent way. * * <code> * * sayAndMakeRequest( * Request * .GET() * .url(testServerUrl().path("search").addQueryParameter("q", "toys"))); * </code> * * * @return a valid host name of your test server (eg http://localhost:8127). * This will be used in the testServerUrl() method. */ public Url testServerUrl() { final String errorText = "If you want to use the TestBrowser you have to override getTestServerUrl()."; logger.error(errorText); throw new IllegalStateException(errorText); } /** * Alternative way to set the output file name. This can be handy when * DocTester is not part of JUnit lifecycle. * * @param name alternative name of output file */ public void setClassNameForDocTesterOutputFile(final String name) { this.classNameForDocTesterOutputFile = name; } }