/tags/fest-swing-junit-1.0a3/src/main/java/org/fest/swing/junit/runner/GUITestRunner.java

http://fest.googlecode.com/ · Java · 161 lines · 103 code · 24 blank · 34 comment · 6 complexity · c723b61bc9392a8b3446c6c1359482e1 MD5 · raw file

  1. /*
  2. * Created on Nov 17, 2007
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
  5. * in compliance with the License. You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software distributed under the License
  10. * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
  11. * or implied. See the License for the specific language governing permissions and limitations under
  12. * the License.
  13. *
  14. * Copyright @2007 the original author or authors.
  15. */
  16. package org.fest.swing.junit.runner;
  17. import java.lang.reflect.InvocationTargetException;
  18. import java.lang.reflect.Method;
  19. import java.util.ArrayList;
  20. import java.util.List;
  21. import org.junit.AfterClass;
  22. import org.junit.BeforeClass;
  23. import org.junit.Test;
  24. import org.junit.internal.runners.*;
  25. import org.junit.runner.Description;
  26. import org.junit.runner.Runner;
  27. import org.junit.runner.notification.Failure;
  28. import org.junit.runner.notification.RunListener;
  29. import org.junit.runner.notification.RunNotifier;
  30. import org.fest.reflect.exception.ReflectionError;
  31. import org.fest.util.Collections;
  32. import static org.fest.reflect.core.Reflection.field;
  33. import static org.fest.util.TypeFilter.byType;
  34. /**
  35. * Understands a JUnit 4 test runner that takes a screenshot of a failed GUI test.
  36. *
  37. * @author Alex Ruiz
  38. * @author Yvonne Wang
  39. */
  40. public class GUITestRunner extends Runner {
  41. private static final List<RunListener> NO_LISTENERS = new ArrayList<RunListener>();
  42. private final List<Method> testMethods;
  43. private final Class<?> testClass;
  44. /**
  45. * Creates a new <code>{@link GUITestRunner}</code>.
  46. * @param testClass the class containing the tests to run.
  47. * @throws InitializationError if something goes wrong when creating this runner.
  48. */
  49. public GUITestRunner(Class<?> testClass) throws InitializationError {
  50. this.testClass = testClass;
  51. testMethods = new TestIntrospector(testClass).getTestMethods(Test.class);
  52. validate();
  53. }
  54. private void validate() throws InitializationError {
  55. MethodValidator methodValidator= new MethodValidator(testClass);
  56. methodValidator.validateMethodsForDefaultRunner();
  57. methodValidator.assertValid();
  58. }
  59. /**
  60. * Run the tests for this runner, taking screenshots of failing tests.
  61. * @param notifier will be notified of events while tests are being run, started, finishing, and failing.
  62. */
  63. @Override public void run(RunNotifier notifier) {
  64. addFailedGUITestListenerTo(notifier);
  65. new InnerRunner(notifier).runProtected();
  66. removeFailedGUITestListenersFrom(notifier);
  67. }
  68. private void addFailedGUITestListenerTo(RunNotifier notifier) {
  69. if (!failedGUITestListenersIn(notifier).isEmpty()) return;
  70. notifier.addListener(new FailedGUITestListener());
  71. }
  72. private void removeFailedGUITestListenersFrom(RunNotifier notifier) {
  73. for(RunListener listener : failedGUITestListenersIn(notifier))
  74. notifier.removeListener(listener);
  75. }
  76. private List<? extends RunListener> failedGUITestListenersIn(RunNotifier notifier) {
  77. List<RunListener> listeners = listenersIn(notifier);
  78. if (listeners.isEmpty()) return NO_LISTENERS;
  79. return Collections.filter(listeners, byType(FailedGUITestListener.class));
  80. }
  81. @SuppressWarnings("unchecked")
  82. private List<RunListener> listenersIn(RunNotifier notifier) {
  83. try {
  84. return field("fListeners").ofType(List.class).in(notifier).get();
  85. } catch (ReflectionError e) {
  86. return NO_LISTENERS;
  87. }
  88. }
  89. final void doRun(RunNotifier notifier) {
  90. if (testMethods.isEmpty()) notifier.testAborted(getDescription(), new Exception("No runnable methods"));
  91. for (Method method : testMethods)
  92. invokeTestMethod(method, notifier);
  93. }
  94. private void invokeTestMethod(Method method, RunNotifier notifier) {
  95. Object test;
  96. try {
  97. test = testClass.getConstructor().newInstance();
  98. } catch (InvocationTargetException e) {
  99. notifier.testAborted(methodDescription(method), e.getCause());
  100. return;
  101. } catch (Exception e) {
  102. notifier.testAborted(methodDescription(method), e);
  103. return;
  104. }
  105. createMethodRunner(test, method, notifier).run();
  106. }
  107. private TestMethodRunner createMethodRunner(Object test, Method method, RunNotifier notifier) {
  108. return new TestMethodRunner(test, method, notifier, methodDescription(method));
  109. }
  110. final Class<?> testClass() { return testClass; }
  111. /**
  112. * Returns a <code>{@link Description}</code> showing the tests to be run by the receiver.
  113. * @return a <code>Description</code> showing the tests to be run by the receiver.
  114. */
  115. @Override public Description getDescription() {
  116. Description spec= Description.createSuiteDescription(testClass.getName());
  117. for (Method method : testMethods)
  118. spec.addChild(methodDescription(method));
  119. return spec;
  120. }
  121. private Description methodDescription(Method method) {
  122. return new GUITestDescription(testClass, method);
  123. }
  124. private class InnerRunner extends BeforeAndAfterRunner {
  125. private final RunNotifier notifier;
  126. InnerRunner(RunNotifier notifier) {
  127. super(testClass(), BeforeClass.class, AfterClass.class, null);
  128. this.notifier = notifier;
  129. }
  130. @Override protected void runUnprotected() {
  131. doRun(notifier);
  132. }
  133. @Override protected void addFailure(Throwable targetException) {
  134. notifier.fireTestFailure(new Failure(getDescription(), targetException));
  135. }
  136. }
  137. }