001/** 002 * Copyright (C) 2011 rwoo@gmx.de 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package com.googlecode.catchexception; 017 018import org.mockito.cglib.proxy.MethodInterceptor; 019 020import com.googlecode.catchexception.apis.CatchExceptionBdd; 021import com.googlecode.catchexception.apis.CatchExceptionHamcrestMatchers; 022import com.googlecode.catchexception.internal.DelegatingInterceptor; 023import com.googlecode.catchexception.internal.ExceptionHolder; 024import com.googlecode.catchexception.internal.ExceptionProcessingInterceptor; 025import com.googlecode.catchexception.internal.InterfaceOnlyProxyFactory; 026import com.googlecode.catchexception.internal.SubclassProxyFactory; 027 028/** 029 * The methods of this class catch and verify exceptions in <em>a single line of 030 * code</em> and make them available for further analysis. 031 * <p> 032 * This Javadoc content is also available on the <a 033 * href="http://code.google.com/p/catch-exception/" >catch-exception</a> web 034 * page. 035 * 036 * <h1>Documentation</h1> 037 * <p> 038 * <b> <a href="#1">1. How to use catch-exception?</a><br/> 039 * <a href="#2">2. What is this stuff actually good for?</a> <br/> 040 * <a href="#3">3. How does it work internally?</a><br/> 041 * <a href="#4">4. When is the caught exception reset?</a><br/> 042 * <a href="#5">5. My code throws a ClassCastException. Why?</a> <br/> 043 * <a href="#6">6. The exception is not caught. Why?</a> <br/> 044 * <a href="#7">7. Do I have to care about memory leaks?</a> <br/> 045 * <a href="#8">8. The caught exception is not available in another thread. 046 * Why?</a><br/> 047 * <a href="#9">9. How do I catch an exception thrown by a static method?</a> <br/> 048 * <a href="#11">11. Can I catch errors instead of exceptions?</a> <br/> 049 * 050 * 051 * 052 * </b> 053 * <p> 054 * <h3 id="1">1. How to use catch-exception?</h3> 055 * <p> 056 * The most basic usage is: 057 * <code><pre class="prettyprint lang-java">import static com.googlecode.catchexception.CatchException.*; 058 059// call customerService.prepareBilling(Prize.Zero) 060// and catch the exception if any is thrown 061catchException(customerService).prepareBilling(Prize.Zero); 062 063// assert that an IllegalArgumentException was thrown 064assert caughtException() instanceof IllegalArgumentException;</pre></code> 065 * <p> 066 * You can combine the two lines of code in a single one if you like: 067 * <code><pre class="prettyprint lang-java">// call customerService.prepareBilling(Prize.Zero) 068// and throw an ExceptionNotThrownAssertionError if 069// the expected exception is not thrown 070verifyException(customerService, IllegalArgumentException.class).prepareBilling(Prize.Zero);</pre></code> 071 * There is a minor difference between both variants. In the first variant you 072 * must start the JVM with option <code>-ea</code> to enable the assertion. The 073 * second variant does not use JDK assertions and ,therefore, always verifies 074 * the caught exception. 075 * <p> 076 * A third variant allows you to select the type of exceptions you want to catch 077 * (no verification involved): 078 * <code><pre class="prettyprint lang-java">// catch IllegalArgumentExceptions but no other exceptions 079catchException(customerService, IllegalArgumentException.class).prepareBilling(Prize.Zero);</pre></code> 080 * <p> 081 * The fourth and last variant verifies that some exception is thrown, i.e. the 082 * type of the exception does not matter: 083 * <code><pre class="prettyprint lang-java">verifyException(customerService).prepareBilling(Prize.Zero);</pre></code> 084 * <p> 085 * In all variants you can use <code>caughtException()</code> afterwards to 086 * inspect the caught exception. 087 * <p> 088 * Finally, there some alternative ways to catch and verify exceptions: 089 * <ul> 090 * <li>{@link CatchExceptionBdd} - a BDD-like approach, 091 * <li> {@link CatchExceptionHamcrestMatchers} - Hamcrest assertions 092 * </ul> 093 * <h3 id="2">2. What is this stuff actually good for?</h3> 094 * <p> 095 * This class targets concise and robust code in tests. Dadid Saff, a commiter 096 * to JUnit, has <a 097 * href="http://shareandenjoy.saff.net/2006/12/assertthrownexception_20.html" 098 * >discussed</a> this approach in 2007. Let me summarize the arguments here. 099 * <p> 100 * There are two advantages of the approach proposed here in comparison to the 101 * use of try/catch blocks. 102 * <ul> 103 * <li>The test is more concise and easier to read. 104 * <li>The test cannot be corrupted by a missing assertion. Assume you forgot to 105 * type <code>fail()</code> behind the method call that is expected to throw an 106 * exception. 107 * </ul> 108 * <p> 109 * There are also some advantages of this approach in comparison to test 110 * runner-specific mechanisms that catch and verify exceptions. 111 * <ul> 112 * <li>A single test can verify more than one thrown exception. 113 * <li>The test can verify the properties of the thrown exception after the 114 * exception is caught. 115 * <li>The test can specify by which method call the exception must be thrown. 116 * <li>The test does not depend on a specific test runner (JUnit4, TestNG). 117 * </ul> 118 * <p> 119 * <h3 id="3">3. How does it work internally?</h3> 120 * <p> 121 * The method <code>catchException(obj)</code> wraps the given object with a 122 * proxy that catches the exception, then (optionally) verifies the exception, 123 * and finally attaches the exception to the current <a 124 * name="threadlocal">thread</a> for further analysis. The <a 125 * href="#proxies">known limitations</a> for proxies apply. 126 * <p> 127 * Is both memory consumption and runtime a concern for you? Then use try/catch 128 * blocks instead of this class. Because in this case the creation of proxies is 129 * an unnecessary overhead. If only either memory consumption or runtime is an 130 * issue for you, feel free to configure the cache of the underlying proxy 131 * factories as appropriate. 132 * <h3 id="4">4. When is the caught exception reset?</h3> 133 * <p> 134 * The Method {@link #caughtException()} returns the exception thrown by the 135 * last method call on a proxied object in the current thread, i.e. it is reset 136 * by calling a method on the proxied object. If the called method has not 137 * thrown an exception, <code>caughtException()</code> returns null. 138 * <p> 139 * To reset the caught exception manually, call {@link #resetCaughtException()}. 140 * At the moment there is no way to reset exceptions that have been caught in 141 * other threads. 142 * <h3 id="5"><a name="proxies" />5. My code throws a ClassCastException. Why?</h3> 143 * <p> 144 * Example: 145 * <code><pre class="prettyprint lang-java">StringBuilder sb = new StringBuilder(); 146catchException(sb).charAt(-2); // throws ClassCastException</pre></code> 147 * <p> 148 * Probably you have tested a final class. Proxy factories usually try to 149 * subclass the type of the proxied object. This is not possible if the original 150 * class is final. But there is a way out. If the tested method belongs to an 151 * interface, then you can cast the argument (here: <code>sb</code>) to that 152 * interface or ,easier, change the declared type of the argument to the 153 * interface type. This works because the created proxy is not longer required 154 * to have the same type as the original class but it must only have the same 155 * interface. 156 * <code><pre class="prettyprint lang-java">// first variant 157StringBuilder sb = new StringBuilder(); 158catchException((CharSequence) sb).charAt(-2); // works fine 159 160// second variant 161CharSequence sb = new StringBuilder(); 162catchException(sb).charAt(-2); // works fine</pre></code> If the tested 163 * method does no belong to an interface fall back to the try/catch-blocks or 164 * use <a 165 * href="http://code.google.com/p/catch-exception/wiki/Dependencies">Powermock 166 * </a>. 167 * <code><pre class="prettyprint lang-java">// example for 168 PowerMock with JUnit4 169@RunWith(PowerMockRunner.class) 170@PrepareForTest({ MyFinalType.class }) 171public class MyTest { 172</pre></code> 173 * <h3 id="6">6. The exception is not caught. Why?</h3> 174 * <p> 175 * Example: 176 * <code><pre class="prettyprint lang-java">ServiceImpl impl = new ServiceImpl(); 177catchException(impl).do(); // do() is a final method that throws an exception</pre></code> 178 * <p> 179 * Probably you have tested a final method. If that tested method belongs to an 180 * interface you could use {@link #interfaces(Object)} to fix that problem. But 181 * then the syntax starts to become ugly. 182 * <code><pre class="prettyprint lang-java">Service api = new ServiceImpl(); 183catchException(interfaces(api)).do(); // works fine</pre></code> I recommend 184 * to use try/catch blocks in such cases. 185 * 186 * <h3 id="7">7. Do I have to care about memory leaks?</h3> 187 * <p> 188 * This library uses a {@link ThreadLocal}. ThreadLocals are known to cause 189 * memory leaks if they refer to a class the garbage collector would like to 190 * collect. If you use this library only for testing, then memory leaks do not 191 * worry you. If you use this library for other purposes than testing, you 192 * should care. 193 * <p> 194 * <h3 id="8">8. The caught exception is not available in another thread. Why?</h3> 195 * <p> 196 * The caught exception is saved <a href="#threadlocal">at the thread</a> the 197 * exception is thrown in. This is the reason the exception is not visible 198 * within any other thread. 199 * <h3 id="9">9. How do I catch an exception thrown by a static method?</h3> 200 * <p> 201 * Unfortunately, catch-exception does not support this. Fall back on try/catch 202 * blocks. 203 * <h3 id="10">10. Is there a way to get rid of the throws clause in my test 204 * method?</h3> 205 * <p> 206 * Example: 207 * <code><pre class="prettyprint lang-java">public void testSomething() throws Exception { 208 ... 209 catchException(obj).do(); // do() throws a checked exception</pre></code> No, 210 * although the exception is always caught you cannot omit the throws clause in 211 * your test method. 212 * <h3 id="11">11. Can I catch errors instead of exceptions?</h3> 213 * <p> 214 * Yes, have a look at 215 * {@link com.googlecode.catchexception.throwable.CatchThrowable} (in module 216 * catch-throwable). 217 * 218 * @author rwoo 219 * @since 16.09.2011 220 */ 221public class CatchException { 222 223 /** 224 * Returns the exception caught during the last call on the proxied object 225 * in the current thread. 226 * 227 * @param <E> 228 * This type parameter makes some type casts redundant. 229 * @return Returns the exception caught during the last call on the proxied 230 * object in the current thread - if the call was made through a 231 * proxy that has been created via 232 * {@link #verifyException(Object, Class) verifyException()} or 233 * {@link #catchException(Object, Class) catchException()}. Returns 234 * null the proxy has not caught an exception. Returns null if the 235 * caught exception belongs to a class that is no longer 236 * {@link ClassLoader loaded}. 237 */ 238 public static <E extends Exception> E caughtException() { 239 return ExceptionHolder.<E> get(); 240 } 241 242 /** 243 * Use it to verify that an exception is thrown and to get access to the 244 * thrown exception (for further verifications). 245 * <p> 246 * The following example verifies that obj.doX() throws a Exception: 247 * <code><pre class="prettyprint lang-java">verifyException(obj).doX(); // catch and verify 248assert "foobar".equals(caughtException().getMessage()); // further analysis 249</pre></code> 250 * <p> 251 * If <code>doX()</code> does not throw a <code>Exception</code>, then a 252 * {@link ExceptionNotThrownAssertionError} is thrown. Otherwise the thrown 253 * exception can be retrieved via {@link #caughtException()}. 254 * <p> 255 * 256 * @param <T> 257 * The type of the given <code>obj</code>. 258 * 259 * @param obj 260 * The instance that shall be proxied. Must not be 261 * <code>null</code>. 262 * @return Returns an object that verifies that each invocation on the 263 * underlying object throws an exception. 264 */ 265 public static <T> T verifyException(T obj) { 266 return verifyException(obj, Exception.class); 267 } 268 269 /** 270 * Use it to verify that an exception of specific type is thrown and to get 271 * access to the thrown exception (for further verifications). 272 * <p> 273 * The following example verifies that obj.doX() throws a MyException: 274 * <code><pre class="prettyprint lang-java">verifyException(obj, MyException.class).doX(); // catch and verify 275assert "foobar".equals(caughtException().getMessage()); // further analysis 276</pre></code> 277 * <p> 278 * If <code>doX()</code> does not throw a <code>MyException</code>, then a 279 * {@link ExceptionNotThrownAssertionError} is thrown. Otherwise the thrown 280 * exception can be retrieved via {@link #caughtException()}. 281 * <p> 282 * 283 * @param <T> 284 * The type of the given <code>obj</code>. 285 * 286 * @param <E> 287 * The type of the exception that shall be caught. 288 * @param obj 289 * The instance that shall be proxied. Must not be 290 * <code>null</code>. 291 * @param clazz 292 * The type of the exception that shall be thrown by the 293 * underlying object. Must not be <code>null</code>. 294 * @return Returns an object that verifies that each invocation on the 295 * underlying object throws an exception of the given type. 296 */ 297 public static <T, E extends Exception> T verifyException(T obj, 298 Class<E> clazz) { 299 300 return processException(obj, clazz, true); 301 } 302 303 /** 304 * Use it to catch an exception and to get access to the thrown exception 305 * (for further verifications). 306 * <p> 307 * In the following example you catch exceptions that are thrown by 308 * obj.doX(): 309 * <code><pre class="prettyprint lang-java">catchException(obj).doX(); // catch 310if (caughtException() != null) { 311 assert "foobar".equals(caughtException().getMessage()); // further analysis 312}</pre></code> 313 * If <code>doX()</code> throws a exception, then {@link #caughtException()} 314 * will return the caught exception. If <code>doX()</code> does not throw a 315 * exception, then {@link #caughtException()} will return <code>null</code>. 316 * <p> 317 * 318 * @param <T> 319 * The type of the given <code>obj</code>. 320 * 321 * @param obj 322 * The instance that shall be proxied. Must not be 323 * <code>null</code>. 324 * @return Returns a proxy for the given object. The proxy catches 325 * exceptions of the given type when a method on the proxy is 326 * called. 327 */ 328 public static <T> T catchException(T obj) { 329 330 return processException(obj, Exception.class, false); 331 } 332 333 /** 334 * Use it to catch an exception of a specific type and to get access to the 335 * thrown exception (for further verifications). 336 * <p> 337 * In the following example you catch exceptions of type MyException that 338 * are thrown by obj.doX(): 339 * <code><pre class="prettyprint lang-java">catchException(obj, MyException.class).doX(); // catch 340if (caughtException() != null) { 341 assert "foobar".equals(caughtException().getMessage()); // further analysis 342}</pre></code> 343 * If <code>doX()</code> throws a <code>MyException</code>, then 344 * {@link #caughtException()} will return the caught exception. If 345 * <code>doX()</code> does not throw a <code>MyException</code>, then 346 * {@link #caughtException()} will return <code>null</code>. If 347 * <code>doX()</code> throws an exception of another type, i.e. not a 348 * subclass but another class, then this exception is not thrown and 349 * {@link #caughtException()} will return <code>null</code>. 350 * <p> 351 * 352 * @param <T> 353 * The type of the given <code>obj</code>. 354 * 355 * @param <E> 356 * The type of the exception that shall be caught. 357 * @param obj 358 * The instance that shall be proxied. Must not be 359 * <code>null</code>. 360 * @param clazz 361 * The type of the exception that shall be caught. Must not be 362 * <code>null</code>. 363 * @return Returns a proxy for the given object. The proxy catches 364 * exceptions of the given type when a method on the proxy is 365 * called. 366 */ 367 public static <T, E extends Exception> T catchException(T obj, 368 Class<E> clazz) { 369 370 return processException(obj, clazz, false); 371 } 372 373 /** 374 * Creates a proxy that processes exceptions thrown by the underlying 375 * object. 376 * <p> 377 * Delegates to 378 * {@link SubclassProxyFactory#createProxy(Class, MethodInterceptor)} which 379 * itself might delegate to 380 * {@link InterfaceOnlyProxyFactory#createProxy(Class, MethodInterceptor)}. 381 */ 382 @SuppressWarnings("javadoc") 383 private static <T, E extends Exception> T processException(T obj, 384 Class<E> exceptionClazz, boolean assertException) { 385 386 if (obj == null) { 387 throw new IllegalArgumentException("obj must not be null"); 388 } 389 390 return new SubclassProxyFactory().<T> createProxy(obj.getClass(), 391 new ExceptionProcessingInterceptor<E>(obj, exceptionClazz, 392 assertException)); 393 394 } 395 396 /** 397 * Returns a proxy that implements all interfaces of the underlying object. 398 * 399 * @param <T> 400 * must be an interface the object implements 401 * @param obj 402 * the object that created proxy will delegate all calls to 403 * @return Returns a proxy that implements all interfaces of the underlying 404 * object and delegates all calls to that underlying object. 405 */ 406 public static <T> T interfaces(T obj) { 407 408 if (obj == null) { 409 throw new IllegalArgumentException("obj must not be null"); 410 } 411 412 return new InterfaceOnlyProxyFactory().<T> createProxy(obj.getClass(), 413 new DelegatingInterceptor(obj)); 414 } 415 416 /** 417 * Sets the {@link #caughtException() caught exception} to null. This does 418 * not affect exceptions saved at threads other than the current one. 419 * <p> 420 * Actually you probably never need to call this method because each method 421 * call on a proxied object in the current thread resets the caught 422 * exception. But if you want to improve test isolation or if you want to 423 * 'clean up' after testing (to avoid memory leaks), call the method before 424 * or after testing. 425 */ 426 public static void resetCaughtException() { 427 ExceptionHolder.set(null); 428 } 429 430}