/*
* Copyright 2008, Unitils.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.unitils;
import org.testng.IHookCallBack;
import org.testng.IHookable;
import org.testng.ITestResult;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.unitils.core.TestListener;
import org.unitils.core.Unitils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* Base test class that will Unitils-enable your test. This base class will make sure that the
* core unitils test listener methods are invoked in the expected order. See {@link TestListener} for
* more information on the listener invocation order.
*
* @author Tim Ducheyne
* @author Filip Neven
*/
public abstract class UnitilsTestNG implements IHookable {
/* True if beforeTestSetUp was called */
private boolean beforeTestSetUpCalled = false;
/**
* Called before a test of a test class is run. This is where {@link TestListener#afterCreateTestObject(Object)} is called.
*/
@BeforeClass(alwaysRun = true)
protected void unitilsBeforeClass() {
getTestListener().beforeTestClass(this.getClass());
getTestListener().afterCreateTestObject(this);
}
/**
* Called before all test setup. This is where {@link TestListener#beforeTestSetUp} is called.
*
* @param testMethod The test method, not null
*/
@BeforeMethod(alwaysRun = true)
protected void unitilsBeforeTestSetUp(Method testMethod) {
beforeTestSetUpCalled = true;
getTestListener().beforeTestSetUp(this, testMethod);
}
/**
* Called after all test tear down. This is where {@link TestListener#afterTestTearDown} is called.
* <p/>
* NOTE: alwaysRun is enabled to be sure that this method is called even when an exception occurs during
* {@link #unitilsBeforeTestSetUp}.
*
* @param testMethod The test method, not null
*/
@AfterMethod(alwaysRun = true)
protected void unitilsAfterTestTearDown(Method testMethod) {
// alwaysRun is enabled, extra test to ensure that unitilsBeforeTestSetUp was called
if (beforeTestSetUpCalled) {
beforeTestSetUpCalled = false;
getTestListener().afterTestTearDown(this, testMethod);
}
}
/**
* Implementation of the hookable interface to be able to call {@link TestListener#beforeTestMethod} and
* {@link TestListener#afterTestMethod}.
*
* @param callBack the TestNG test callback, not null
* @param testResult the TestNG test result, not null
*/
public void run(IHookCallBack callBack, ITestResult testResult) {
Throwable beforeTestMethodException = null;
try {
getTestListener().beforeTestMethod(this, testResult.getMethod().getMethod());
} catch (Throwable e) {
// hold exception until later, first call afterTestMethod
beforeTestMethodException = e;
}
Throwable testMethodException = null;
if (beforeTestMethodException == null) {
callBack.runTestMethod(testResult);
// Since TestNG calls the method using reflection, the exception is wrapped in an InvocationTargetException
testMethodException = testResult.getThrowable();
if (testMethodException != null && testMethodException instanceof InvocationTargetException) {
testMethodException = ((InvocationTargetException) testMethodException).getTargetException();
}
}
Throwable afterTestMethodException = null;
try {
getTestListener().afterTestMethod(this, testResult.getMethod().getMethod(), beforeTestMethodException != null ? beforeTestMethodException : testMethodException);
} catch (Throwable e) {
afterTestMethodException = e;
}
// if there were exceptions, make sure the exception that occurred first is reported by TestNG
if (beforeTestMethodException != null) {
throwException(beforeTestMethodException);
} else {
// We don't throw the testMethodException, it is already registered by TestNG and will be reported to the user
if (testMethodException == null && afterTestMethodException != null) {
throwException(afterTestMethodException);
}
}
}
/**
* Throws an unchecked excepton for the given throwable.
*
* @param throwable The throwable, not null
*/
protected void throwException(Throwable throwable) {
if (throwable instanceof RuntimeException) {
throw (RuntimeException) throwable;
} else if (throwable instanceof Error) {
throw (Error) throwable;
} else {
throw new RuntimeException(throwable);
}
}
/**
* @return The Unitils test listener
*/
protected TestListener getTestListener() {
return getUnitils().getTestListener();
}
/**
* Returns the default singleton instance of Unitils
*
* @return the Unitils instance, not null
*/
protected Unitils getUnitils() {
return Unitils.getInstance();
}
}