package org.test4j.testng; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.test4j.module.ICore; import org.test4j.module.core.TestContext; import org.test4j.module.core.TestListener; import org.test4j.module.core.utility.ListenerExecutor; import org.test4j.module.core.utility.ModulesManager; import org.test4j.module.jmockit.JMockitModule; import org.test4j.tools.commons.ExceptionWrapper; import org.testng.IHookCallBack; import org.testng.IHookable; import org.testng.ITestContext; import org.testng.ITestResult; /** * Base testNG class that will enable specify features. * * @author darui.wudr */ public abstract class Test4JHookable implements IHookable, ICore { protected final static String TEST_CLAZZ_INFO = "%s executing test class[%s] in thread[%d]."; protected final static String TEST_METHOD_INFO = "%s executing test method[%s . %s ()] in thread[%d]."; /** * test4j @BeforeClass 方法抛出的异常 */ protected Throwable error_setup_class = null; /** * test4j @BeforeMethod 方法抛出的异常 */ protected Throwable error_setup_method = null; /** * 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 */ @Override public void run(IHookCallBack callBack, ITestResult testResult) { this.doesMethodHasSetupError(); Method testedMethod = testResult.getMethod().getConstructorOrMethod().getMethod(); Throwable beforeRunningError = ListenerExecutor.executeBeforeRunningEvents(this, testedMethod); Throwable testedMethodError = null; try { if (beforeRunningError == null) { callBack.runTestMethod(testResult); testedMethodError = this.getTestedMethodError(testResult); } } catch (Throwable e) { testedMethodError = this.getTestedMethodError(testResult); if (testedMethodError == null) { throw TestContext.getMultipleException(e); } } Throwable afterRunnedError = ListenerExecutor.executeAfterRunnedEvents(this, testedMethod, beforeRunningError != null ? beforeRunningError : testedMethodError); this.doesThrowExceptionTeardown(beforeRunningError, testedMethodError, afterRunnedError); } /** * 测试方法是否已经在@BeforeClass和@BeforeMethod中已经有hold的异常,如果有,则抛出异常 */ private void doesMethodHasSetupError() { ExceptionWrapper.throwRuntimeException("test4j tested class setup error.", error_setup_class); ExceptionWrapper.throwRuntimeException("test4j tested method setup error", error_setup_method); } /** * 测试方法结束后是否抛出异常<br> * 只抛出beforeRunning和afterRunned的异常,testedMethod的异常testng自己会处理<br> * We don't throw the testMethodException, it is already registered by * TestNG and will be reported to the user * * @param beforeRunningError * @param testedMethodError * @param afterRunnedError */ private void doesThrowExceptionTeardown(Throwable beforeRunningError, Throwable testedMethodError, Throwable afterRunnedError) { ExceptionWrapper.throwRuntimeException(beforeRunningError); Throwable teardowError = testedMethodError != null ? null : afterRunnedError; ExceptionWrapper.throwRuntimeException(teardowError); } /** * 获取测试执行过程中的异常<br> * Since TestNG calls the method using reflection<br> * the exception is wrapped in an InvocationTargetException * * @param testResult 测试结果 * @return 异常 */ private Throwable getTestedMethodError(ITestResult testResult) { Throwable testedMethodError = testResult.getThrowable(); if (testedMethodError != null && testedMethodError instanceof InvocationTargetException) { testedMethodError = ((InvocationTargetException) testedMethodError).getTargetException(); } return testedMethodError; } private Boolean isJMockitEnabled = null; protected void dealJMockitTestDecorator(ITestContext context) { if (isJMockitEnabled != null) { return; } this.isJMockitEnabled = ModulesManager.isModuleEnabled(JMockitModule.class); if (this.isJMockitEnabled == false) { return; } new JMockitInvokaeMethodListener(context); this.isJMockitEnabled = true; } }