| /* |
| * Copyright (c) 2007 Mockito contributors |
| * This program is made available under the terms of the MIT License. |
| */ |
| package org.mockito.runners;
|
|
|
| import java.lang.reflect.InvocationTargetException;
|
|
|
| import org.junit.runner.Description;
|
| import org.junit.runner.Runner;
|
| import org.junit.runner.manipulation.Filter;
|
| import org.junit.runner.manipulation.Filterable;
|
| import org.junit.runner.manipulation.NoTestsRemainException;
|
| import org.junit.runner.notification.Failure;
|
| import org.junit.runner.notification.RunListener;
|
| import org.junit.runner.notification.RunNotifier;
|
| import org.junit.runners.BlockJUnit4ClassRunner;
|
| import org.mockito.internal.debugging.WarningsCollector;
|
| import org.mockito.internal.runners.RunnerFactory;
|
| import org.mockito.internal.runners.RunnerImpl;
|
| import org.mockito.internal.util.ConsoleMockitoLogger;
|
| import org.mockito.internal.util.MockitoLogger;
|
|
|
| /**
|
| * Uses <b>JUnit 4.5</b> runner {@link BlockJUnit4ClassRunner}.
|
| * <p>
|
| * Experimental implementation that suppose to improve tdd/testing experience.
|
| * Don't hesitate to send feedback to mockito@googlegroups.com
|
| * <b>It is very likely it will change in the next version!</b>
|
| * <p>
|
| * This runner does exactly what {@link MockitoJUnitRunner} does but also
|
| * prints warnings that might be useful.
|
| * The point is that Mockito should help the tdd developer to quickly figure out if the test fails for the right reason.
|
| * Then the developer can implement the functionality.
|
| * Also when the test fails it should be easy to figure out why the test fails.
|
| * <p>
|
| * Sometimes when the test fails, the underlying reason is that stubbed method was called with wrong arguments.
|
| * Sometimes it fails because one forgets to stub a method or forgets to call a stubbed method.
|
| * All above problems are not immediately obvious.
|
| * <p>
|
| * One way of approaching this problem is full-blown 'expect' API.
|
| * However it means the 'expectations upfront' business which is not in line with core Mockito concepts.
|
| * After all, the essence of testing are <b>explicit assertions</b> that are described consistently at the <b>bottom of the test</b> method.
|
| * <p>
|
| * Here's the experiment: a warning is printed to the standard output if the test fails.
|
| * Also, you get a clickabe link to the line of code. You can immediately jump to the place in code where the potential problem is.
|
| * <p>
|
| * Let's say your test fails on assertion.
|
| * Let's say the underlying reason is a stubbed method that was called with different arguments:
|
| * <pre class="code"><code class="java">
|
| * //test:
|
| * Dictionary dictionary = new Dictionary(translator);
|
| * when(translator.translate("Mockito")).thenReturn("cool framework");
|
| * String translated = dictionary.search("Mockito");
|
| * assertEquals("cool framework", translated);
|
| *
|
| * //code:
|
| * public String search(String word) {
|
| * ...
|
| * return translator.translate("oups");
|
| *
|
| * </code></pre>
|
| * On standard output you'll see something like that:
|
| * <pre class="code"><code class="java">
|
| * [Mockito] Warning - stubbed method called with different arguments.
|
| * Stubbed this way:
|
| * translator.translate("Mockito");
|
| * org.dictionary.SmartDictionaryTest.shouldFindTranslation(SmartDictionaryTest.java:27)
|
| *
|
| * But called with different arguments:
|
| * translator.translate("oups");
|
| * org.dictionary.SmartDictionary.search(SmartDictionary.java:15)
|
| * </code></pre>
|
| * <p>
|
| * Note that it is just a warning, not an assertion.
|
| * The test fails on assertion because it's the assertion's duty to document what the test stands for and what behavior it proves.
|
| * Warnings just makes it quicker to figure out if the test fails for the right reason.
|
| * <p>
|
| * Note that code links printed to the console are clickable in any decent IDE (e.g. Eclipse).
|
| * <p>
|
| * So far I identified 2 cases when warnings are printed:
|
| * <li>unsued stub</li>
|
| * <li>stubbed method but called with different arguments</li>
|
| * <p>
|
| * <br/>
|
| * <p>
|
| * Do you think it is useful or not? Drop us an email at mockito@googlegroups.com
|
| */
|
| public class ConsoleSpammingMockitoJUnitRunner extends Runner implements Filterable {
|
|
|
| private final MockitoLogger logger;
|
| private RunnerImpl runner;
|
|
|
| public ConsoleSpammingMockitoJUnitRunner(Class<?> klass) throws InvocationTargetException {
|
| this(new ConsoleMockitoLogger(), new RunnerFactory().create(klass));
|
| }
|
|
|
| ConsoleSpammingMockitoJUnitRunner(MockitoLogger logger, RunnerImpl runnerImpl) {
|
| this.runner = runnerImpl;
|
| this.logger = logger;
|
| }
|
|
|
| @Override
|
| public void run(RunNotifier notifier) {
|
| RunListener listener = new RunListener() {
|
| WarningsCollector warningsCollector;
|
|
|
| @Override
|
| public void testStarted(Description description) throws Exception {
|
| warningsCollector = new WarningsCollector();
|
| }
|
|
|
| @Override public void testFailure(Failure failure) throws Exception {
|
| logger.log(warningsCollector.getWarnings());
|
| }
|
| };
|
|
|
| notifier.addListener(listener);
|
|
|
| runner.run(notifier);
|
| }
|
|
|
| @Override
|
| public Description getDescription() {
|
| return runner.getDescription();
|
| }
|
|
|
| public void filter(Filter filter) throws NoTestsRemainException {
|
| //filter is required because without it UnrootedTests show up in Eclipse
|
| runner.filter(filter);
|
| }
|
| } |