====== Integration with TestNG ====== {{keywords>Integration with TestNG}} Powermockを%%TestNG%%と一緒に使う為に必要な設定をメモとして残しておく。\\ 基本的に、testプロジェクトはMavenプロジェクトとして作成することを前提している。 Mavenプロジェクトのproperties設定を以下に示す。 ^key^value^comment^ |project.build.sourceEncoding|UTF-8| | |java.version|1.8| | |powermock.version|2.0.9| | |log4j.version|2.17.1| | Mavenプロジェクトのplugin設定を以下に示す。 ora.apache.maven.plugins maven-compiler-plugin 3.8.1 ${java.version} ${java.version} %%TestNG%%と一緒に使う場合は、下記モジュールの導入が必要だ。\\ 必要モジュールを下記に示す。 ^groupId^artifactId^version^scope^ |org.powermock|powermock-module-testng|${powermock.version}|test| |org.powermock|powermock-api-mockito2|${powermock.version}|test| その他、必要モジュールを導入するが、基本的に入れるモジュールを以下に示す。 ^groupId^artifactId^version^scope^ |org.dbunit|dbunit|2.7.2| | |org.apache.commons|commons-lang3|3.12| | |org.apache.poi|poi|5.1.0| | |org.apache.poi|poi-ooxml|5.1.0| | |commons-io|commons-io|2.11.0| | |commons-beanutils|commons-beanutils|1.9.3| | |com.google.inject|guice|5.0.1| | |org.apache.logging.log4j|log4j-1.2-api|${log4j.version}|test| |org.apache.logging.log4j|log4j-api|${log4j.version}|test| |org.apache.logging.log4j|log4j-core|${log4j.version}|test| ====== Common Parent Test Class ====== Testクラスが共通で継承する親クラスについて、サンプルとして残しておく。\\ @Listeners({CustomTestMethodListener.class}) @PowerMockIgnore({"javax.management.*", "javax.security.auth.x500.*", "javax.net.ssl.*", "oracle.jdbc.*", "javax.sql.*", "com.microsoft.sqlserver.*"}) public abstract class AbstractCustomTestCase extends PowerMockTestCase { /** DBUnitのテスター */ protected IDatabaseTester databaseTester; //overwrite createWorkbook for Xlsx data set //DBUnitでXlsxをITableとして使えるよう、override protected final XlsDataSetWriter xlsxWriter = new XlsDataSetWriter() { /* (non-Javadoc) * @see org.dbunit.dataset.excel.XlsDataSetWriter#createWorkbook() */ @Override protected Workbook createWorkbook() { return new XSSFWorkbook(); } }; //***** public method ***** //***** protected method ***** @BeforeClass protected void setUp() throws Exception { setUpLog4j(); setUpDbunitTester(); prepareSpecific(); } @AfterClass protected void tearDown() throws Exception { databaseTester.setTearDownOperation(DatabaseOperation.NONE); databaseTester.onTearDown(); tearDownHook(); } protected abstract void prepareSpecific() throws Exception; protected void tearDownHook() throws Exception { //NOP } //***** private method ***** // Creates a new JdbcDatabaseTester private void setUpDbunitTester() throws Exception { DataSource _ds = DataSourceLocator.getDataSource(DBConstants.EPADS); databaseTester = new DataSourceDatabaseTester(_ds); // ---------------------------------- // Database config // ---------------------------------- DatabaseConfig _config = databaseTester.getConnection().getConfig(); _config.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new OracleDataTypeFactory()); } //Enable Log4j 1.x bridge private void setUpLog4j() { System.setProperty("log4j1.compatibility", "true"); } } ===== @Listeners ===== Test実行中のあるフェーズで共通の処理を追加したい場合の為に、%%TestNG%%ではListener((https://testng.org/doc/documentation-main.html#testng-listeners))というInterfaceを提供している。\\ 通常テストを行う際、メソッド1個のみ実行することはない。\\ 今なんのメソッドが実行されたかをコンソールで確認し易いために、%%IInvokeMethodListener%%を実装しておくと便利だ。\\ サンプルのParent Classでは、%%CustomTestMethodListener%%を指定しているが、コードを以下に示す。 public class CustomTestMethodListener implements IInvokedMethodListener { //***** injection field ***** //***** constructor ***** //***** public method ***** /** * @see org.testng.IInvokedMethodListener#beforeInvocation(org.testng.IInvokedMethod, org.testng.ITestResult) */ public void beforeInvocation(IInvokedMethod method, ITestResult testResult) { if (method.isTestMethod()) { System.out.println("on test method " + method.getTestMethod().getMethodName() + " start"); //parameters System.out.println("parameters:" + ToStringBuilder.reflectionToString(testResult.getParameters(), ToStringStyle.SIMPLE_STYLE)); } } /** * @see org.testng.IInvokedMethodListener#afterInvocation(org.testng.IInvokedMethod, org.testng.ITestResult) */ public void afterInvocation(IInvokedMethod method, ITestResult testResult) { //NOP } } ===== @MockPolicy ===== Powermockをlog4j又はslf4jと一緒に使う場合、次のエラーが発生することがある。 log4j:ERROR A "org.apache.log4j.xml.DOMConfigurator" object is not assignable to a "org.apache.log4j.spi.Configurator" variable. log4j:ERROR The class "org.apache.log4j.spi.Configurator" was loaded by log4j:ERROR [org.powermock.core.classloader.MockClassLoader@14a55f2] whereas object of type log4j:ERROR "org.apache.log4j.xml.DOMConfigurator" was loaded by [sun.misc.Launcher$AppClassLoader@92e78c]. log4j:ERROR Could not instantiate configurator [org.apache.log4j.xml.DOMConfigurator]. 解決策はいくつか((https://github.com/powermock/powermock/wiki/FAQ))あるが、簡単なのは、**%%MockPolicy%%** annotationを利用してlog実装体を指定する方法だ。\\ Log4jのみ利用する場合は、**%%@MockPolicy(Log4jMockPolicy.class)%%**\\ Slf4jとLog4jを併用する場合は、**%%@MockPolicy(Slf4jMockPolicy.class)%%**を指定する。 ===== @PowerMockIgnore ===== %%TestNG%%と%%PowerMock%%を同時に使うと、%%TestNG%%の%%ClassLoader%%によりloadingされたクラスが、%%PowerMocker%%の%%ClassLoader%%にloadingされエラーになることがある。\\ それを回避するために、用意されているのが%%@PowerMockIgnore%% annotationになる。 サンプルのParentクラスで指定した設定の意味を次に示す。 ^package or class^目的^ |javax.management.*|DBUnitと統合| |javax.net.ssl.*|DBUnitと統合| |javax.security.auth.x500.*|DBUnitと統合| |oracle.jdbc.*|Oracle接続| |javax.sql.*|SQL Server接続| |com.microsoft.sqlserver.*|SQL Server接続| ====== log4j設定 ====== log4j-2.xのlogging設定ファイルとしてlog4j2-test.xmlをsrc/test/resourcesフォルダーに配置しておく。\\ 設定例を以下に示す。 C:/workspaces/logs/appl ====== logback.xml設定 ====== logback-classicをloggingとして使う場合の設定例を以下に示します。 %d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] - %class{40}.%method:%msg %n ${LOG_DIR}/ecabinet.log ${LOG_DIR}/ecabinet_%d{yyyy-MM-dd}.log 30 %d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] - %class{40}.%method:%msg %n