001/* 002 * Copyright 2015 SirWellington Tech. 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 tech.sirwellington.alchemy.test.junit; 017 018import tech.sirwellington.alchemy.annotations.designs.FluidAPIDesign; 019 020import static org.hamcrest.Matchers.containsString; 021import static org.hamcrest.Matchers.is; 022import static org.hamcrest.Matchers.isA; 023import static org.hamcrest.Matchers.notNullValue; 024import static org.hamcrest.Matchers.nullValue; 025import static org.junit.Assert.assertThat; 026import static tech.sirwellington.alchemy.test.Checks.Internal.checkNotNull; 027 028/** 029 * Makes it easier syntactically using Java 8 to assert an Exception is thrown by a section of code. 030 * You can also perform additional verification on the exception that is thrown. 031 * 032 * Example: 033 * 034 * <pre> 035 * {@code 036 * assertThrows(() -> someFunctionThatThrows()) 037 * .isIntanceOf(RuntimeException.class) 038 * .hasNoCause(); 039 * } 040 * </pre> 041 * 042 * @author SirWellington 043 */ 044@FluidAPIDesign 045public final class ThrowableAssertion 046{ 047 048 /** 049 * Assert that a function throws an exception. 050 * 051 * @param operation The Lambda function that encapsulates code you expect to throw an exception. 052 * 053 * @return 054 * 055 * @throws ExceptionNotThrownException If no exception is thrown. 056 */ 057 public static ThrowableAssertion assertThrows(ExceptionOperation operation) throws ExceptionNotThrownException 058 { 059 checkNotNull(operation, "missing operation"); 060 return new ThrowableAssertion(operation) 061 .execute(); 062 } 063 064 private Throwable caught; 065 private final ExceptionOperation operation; 066 067 private ThrowableAssertion(ExceptionOperation operation) 068 { 069 this.operation = operation; 070 } 071 072 private ThrowableAssertion execute() throws ExceptionNotThrownException 073 { 074 try 075 { 076 operation.call(); 077 } 078 catch (Throwable ex) 079 { 080 this.caught = ex; 081 return this; 082 } 083 throw new ExceptionNotThrownException("Expected an exception"); 084 } 085 086 /** 087 * Check that the Exception is of a particular type. 088 * 089 * @param exceptionClass The expected type of the Exception. 090 * 091 * @return 092 */ 093 public ThrowableAssertion isInstanceOf(Class<? extends Throwable> exceptionClass) 094 { 095 assertThat(caught, isA((Class<Throwable>) exceptionClass)); 096 return this; 097 } 098 099 /** 100 * Checks to make sure the exception contains a certain message. 101 * 102 * @param expectedMessage The exact message expected 103 * 104 * @return 105 */ 106 public ThrowableAssertion hasMessage(String expectedMessage) 107 { 108 assertThat(caught.getMessage(), is(expectedMessage)); 109 return this; 110 } 111 112 /** 113 * Assert that the exception contains a string in its message. 114 * 115 * @param messageString The partial message to expected. 116 * 117 * @return 118 */ 119 public ThrowableAssertion containsInMessage(String messageString) 120 { 121 assertThat(caught.getMessage(), containsString(messageString)); 122 return this; 123 } 124 125 /** 126 * Assert that the exception has no causing exception 127 * 128 * @return 129 */ 130 public ThrowableAssertion hasNoCause() 131 { 132 assertThat(caught.getCause(), nullValue()); 133 return this; 134 } 135 136 /** 137 * Asserts that the Exception has a cause of a particular type. 138 * 139 * @param exceptionClass The type expected. 140 * 141 * @return 142 */ 143 public ThrowableAssertion hasCauseInstanceOf(Class<? extends Throwable> exceptionClass) 144 { 145 assertThat(caught.getCause(), notNullValue()); 146 assertThat(caught.getCause(), isA((Class<Throwable>) exceptionClass)); 147 return this; 148 } 149}