====== 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