001/** 002 * Powerunit - A JDK1.8 test framework 003 * Copyright (C) 2014 Mathieu Boretti. 004 * 005 * This file is part of Powerunit 006 * 007 * Powerunit is free software: you can redistribute it and/or modify 008 * it under the terms of the GNU General Public License as published by 009 * the Free Software Foundation, either version 3 of the License, or 010 * (at your option) any later version. 011 * 012 * Powerunit is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 015 * GNU General Public License for more details. 016 * 017 * You should have received a copy of the GNU General Public License 018 * along with Powerunit. If not, see <http://www.gnu.org/licenses/>. 019 */ 020package ch.powerunit; 021 022import java.util.function.Consumer; 023import java.util.function.Supplier; 024 025import org.mockito.MockitoAnnotations; 026 027/** 028 * Definition of a test rule (modification of a test statement). 029 * <p> 030 * TestRule are the only way (outside of the @Parameters concept) to 031 * provides test fixtures, action before and after tests, etc. Only one 032 * <code>TestRule</code> chain is allowed for a test class. If a test class 033 * extends another one, one chain is allowed for each test class and they will 034 * be chained from the upper class to the lower one. 035 * <p> 036 * Conceptually, a test rule, at execution time, will receive a test statement 037 * as parameter and compute another test statement. 038 * <h3>Test Rule chain</h3> 039 * A test rule chain is public final, non static, field, of type 040 * <code>TestRule</code>. Once you have the outer test rule, it is possible to 041 * chain them by using the {@link #around(TestRule)} or 042 * {@link #around(Supplier)} methods. One single TestRule (which can be used as 043 * a start of the chain, or later), can be builded by : 044 * <ul> 045 * <li>Simply using the constructor (or other way) provided by the rule itself 046 * (for instance see the {@link ch.powerunit.rules.TestContextRule 047 * TestContextRule} rule.</li> 048 * <li>Use the <code>before</code> method that will produce a rule to be 049 * executed before a test ; The <code>after</code> method will do the same, but 050 * with a code to be executed after a test.</li> 051 * </ul> 052 * 053 * <h3>Example</h3> 054 * For instance, for this class: 055 * 056 * <pre> 057 * import org.mockito.Mock; 058 * import org.mockito.Mockito; 059 * import ch.powerunit.Rule; 060 * import ch.powerunit.Test; 061 * import ch.powerunit.TestRule; 062 * import ch.powerunit.TestSuite; 063 * 064 * public class MockitoRuleTest implements TestSuite { 065 * public interface Mockable { 066 * void run(); 067 * } 068 * 069 * @Mock 070 * private Mockable mock; 071 * 072 * @Rule 073 * public final TestRule testRule = mockitoRule() 074 * .around(before(this::prepare)); 075 * 076 * public void prepare() { 077 * Mockito.doThrow(new RuntimeException("test")).when(mock).run(); 078 * } 079 * 080 * @Test 081 * public void testException() { 082 * assertWhen((p) -> mock.run()).throwException( 083 * isA(RuntimeException.class)); 084 * } 085 * 086 * } 087 * </pre> 088 * 089 * In this case, the defined chain, will first apply the rule provided by 090 * <code>mockitoRule</code>, and then apply the rule included inside the 091 * <code>around</code>. The <code>before</code> method usage inside the 092 * <code>around</code> will ensure the method <code>prepare</code> is executed 093 * before each test. 094 * <p> 095 * The sequence of execution, will be : 096 * <ol> 097 * <li>Execute the Mockito initialization.</li> 098 * <li>Execute the method <code>prepare</code>.</li> 099 * <li>Execute the test method <code>testException</code>.</li> 100 * </ol> 101 * 102 * @author borettim 103 * 104 */ 105@FunctionalInterface 106public interface TestRule { 107 /** 108 * The default implementation of test rule. 109 * <p> 110 * The goal of this method is to compute another test statement that will be 111 * the one to be runned. 112 * 113 * @param inner 114 * the inner statement 115 * @return the new statement, as modified by this rule. 116 */ 117 Statement<TestContext<Object>, Throwable> computeStatement( 118 Statement<TestContext<Object>, Throwable> inner); 119 120 /** 121 * Build a before testrule. 122 * <p> 123 * The passed piece of code (which can for instance an inline definition or 124 * a reference to a method) that must be executed before the test itself. 125 * 126 * @param before 127 * the code to be used before 128 * @return the rule chain. 129 */ 130 static TestRule before(Runnable before) { 131 return (i) -> (p) -> { 132 before.run();// NOSONAR - It is OK to run here 133 i.run(p); 134 }; 135 } 136 137 /** 138 * Build a before testrule. 139 * <p> 140 * The passed piece of code (which can for instance an inline definition or 141 * a reference to a method) that must be executed before the test itself. 142 * 143 * @param before 144 * the code to be used before 145 * @return the rule chain. 146 * @since 0.4.0 147 */ 148 static TestRule before(Consumer<TestContext<Object>> before) { 149 return (i) -> (p) -> { 150 before.accept(p); 151 i.run(p);// NOSONAR - It is OK to run here 152 }; 153 } 154 155 /** 156 * Build a after testrule. 157 * <p> 158 * The passed piece of code (which can for instance an inline definition or 159 * a reference to a method) that must be executed after the test itself. 160 * 161 * @param after 162 * the code to be used after 163 * @return the rule chain. 164 */ 165 static TestRule after(Runnable after) { 166 return (i) -> (p) -> { 167 try { 168 i.run(p);// NOSONAR - It is OK to run here 169 } finally { 170 after.run();// NOSONAR - It is OK to run here 171 } 172 }; 173 } 174 175 /** 176 * Build a after testrule. 177 * <p> 178 * The passed piece of code (which can for instance an inline definition or 179 * a reference to a method) that must be executed after the test itself. 180 * 181 * @param after 182 * the code to be used after 183 * @return the rule chain. 184 * @since 0.4.0 185 */ 186 static TestRule after(Consumer<TestContext<Object>> after) { 187 return (i) -> (p) -> { 188 try { 189 i.run(p);// NOSONAR - It is OK to run here 190 } finally { 191 after.accept(p); 192 } 193 }; 194 } 195 196 /** 197 * Add an inner rule. 198 * 199 * @param inner 200 * the inner rule 201 * @return the rule chain. 202 */ 203 default TestRule around(TestRule inner) { 204 return around(() -> inner); 205 } 206 207 /** 208 * Add an inner rule. 209 * <p> 210 * This inner rule is created just before usage, thanks to the 211 * {@link Supplier} object. This can be used for the case when one rule 212 * depend on the outcome of a previous one. 213 * 214 * @param inner 215 * the supplier of the inner rule 216 * @return the rule chain. 217 */ 218 default TestRule around(Supplier<TestRule> inner) { 219 return (i) -> computeStatement((p) -> inner.get().computeStatement(i) 220 .run(p)); 221 } 222 223 /** 224 * Create a rule to support mockito. 225 * 226 * @return the mockitor rule 227 */ 228 static TestRule mockitoRule() { 229 return (i) -> Statement.around(i, (p) -> { 230 MockitoAnnotations.initMocks(p.getTestSuiteObject()); 231 }, (p) -> { 232 // Do nothing as default 233 }); 234 } 235}