Skip to content

Commit

Permalink
test-util: added Abstract{Unit,Spring}Test classes and UnitTestMixin
Browse files Browse the repository at this point in the history
This helps with test method lifecycle:
- printing header/footer of the test
- providing typical when/then methods and storing thread-local context
It's better to use one of Abstract*Test classes instead of mixin
interface directly.
  • Loading branch information
virgo47 committed Feb 28, 2020
1 parent bade6a0 commit 1b2a4f0
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 5 deletions.
5 changes: 5 additions & 0 deletions infra/test-util/pom.xml
Expand Up @@ -61,6 +61,11 @@
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>

<!-- Do we need this? Why? -->
<dependency>
<groupId>org.apache.felix</groupId>
Expand Down
@@ -0,0 +1,52 @@
/*
* Copyright (C) 2010-2020 Evolveum and contributors
*
* This work is dual-licensed under the Apache License 2.0
* and European Union Public License. See LICENSE file for details.
*/
package com.evolveum.midpoint.test.util;

import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.ITestResult;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;

import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;

/**
* Base test class for tests integrated with Spring providing {@link UnitTestMixin} implementation.
* Can be extended by any unit test class that would otherwise extend
* {@link AbstractTestNGSpringContextTests}.
*/
public abstract class AbstractSpringTest extends AbstractTestNGSpringContextTests
implements UnitTestMixin {

private static final ThreadLocal<ITestResult> TEST_CONTEXT_THREAD_LOCAL = new ThreadLocal<>();

/**
* Hides parent's logger, but that one is from commons-logging and we don't want that.
*/
protected final Trace logger = TraceManager.getTrace(getClass());

@BeforeMethod
public void startTestContext(ITestResult testResult) {
Class<?> testClass = testResult.getMethod().getTestClass().getRealClass();
String testMethodName = testResult.getMethod().getMethodName();
TestUtil.displayTestTitle(testClass.getSimpleName() + "." + testMethodName);

TEST_CONTEXT_THREAD_LOCAL.set(testResult);
}

@AfterMethod
public void finishTestContext(ITestResult testResult) {
TEST_CONTEXT_THREAD_LOCAL.remove();

displayDefaultTestFooter(testResult);
}

@Override
public String getTestNameShort() {
return TEST_CONTEXT_THREAD_LOCAL.get().getMethod().getMethodName();
}
}
@@ -0,0 +1,46 @@
/*
* Copyright (C) 2010-2020 Evolveum and contributors
*
* This work is dual-licensed under the Apache License 2.0
* and European Union Public License. See LICENSE file for details.
*/
package com.evolveum.midpoint.test.util;

import org.testng.ITestResult;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;

import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;

/**
* Base test class providing basic {@link UnitTestMixin} implementation.
* Can be extended by any unit test class that otherwise doesn't extend anything.
*/
public abstract class AbstractUnitTest implements UnitTestMixin {

private static final ThreadLocal<ITestResult> TEST_CONTEXT_THREAD_LOCAL = new ThreadLocal<>();

protected final Trace logger = TraceManager.getTrace(getClass());

@BeforeMethod
public void startTestContext(ITestResult testResult) {
Class<?> testClass = testResult.getMethod().getTestClass().getRealClass();
String testMethodName = testResult.getMethod().getMethodName();
TestUtil.displayTestTitle(testClass.getSimpleName() + "." + testMethodName);

TEST_CONTEXT_THREAD_LOCAL.set(testResult);
}

@AfterMethod
public void finishTestContext(ITestResult testResult) {
TEST_CONTEXT_THREAD_LOCAL.remove();

displayDefaultTestFooter(testResult);
}

@Override
public String getTestNameShort() {
return TEST_CONTEXT_THREAD_LOCAL.get().getMethod().getMethodName();
}
}
Expand Up @@ -185,12 +185,12 @@ public static void displayWhen(String what) {
LOGGER.info(TEST_LOG_SECTION_PREFIX + " WHEN " + what + TEST_LOG_SECTION_SUFFIX);
}

public static void displayWhen(String testName, String part) {
if (part == null) {
part = "";
public static void displayWhen(String testName, String description) {
if (description == null) {
description = "";
}
System.out.println(TEST_OUT_SECTION_PREFIX + testName + ": WHEN " + part + TEST_OUT_SECTION_SUFFIX);
LOGGER.info(TEST_LOG_SECTION_PREFIX + testName + ": WHEN " + part + TEST_LOG_SECTION_SUFFIX);
System.out.println(TEST_OUT_SECTION_PREFIX + testName + ": WHEN " + description + TEST_OUT_SECTION_SUFFIX);
LOGGER.info(TEST_LOG_SECTION_PREFIX + testName + ": WHEN " + description + TEST_LOG_SECTION_SUFFIX);
}

// TODO change like when
Expand Down
@@ -0,0 +1,78 @@
/*
* Copyright (C) 2010-2020 Evolveum and contributors
*
* This work is dual-licensed under the Apache License 2.0
* and European Union Public License. See LICENSE file for details.
*/
package com.evolveum.midpoint.test.util;

import org.testng.ITestResult;

/**
* Mixin with various utility methods - typically delegating to {@link TestUtil}.
*/
public interface UnitTestMixin {

/**
* Returns short test name - typically just a method name (without class).
*/
String getTestNameShort();

/**
* Displays "when" subsection header with test name.
* Even better, use {@link #when(String)} and provide human readable description.
*/
default void when() {
when(null);
}

/**
* Displays "when" subsection header with test name and provided description (nullable).
*/
default void when(String description) {
TestUtil.displayWhen(getTestNameShort(), description);
}

/**
* Displays "then" subsection header with test name.
* Even better, use {@link #then(String)} and provide human readable description.
*/
default void then() {
then(null);
}

/**
* Displays "then" subsection header with test name and provided description (nullable).
*/
default void then(String description) {
TestUtil.displayThen(getTestNameShort(), description);
}

// TODO introduce "expect" as well? sometimes we use when/then combined section
// in such a case instead of "given - when/then" we should have "given - expect"

// TODO inline after merge to master
default void displayWhen() {
when();
}

// TODO inline after merge to master
default void displayWhen(String description) {
when(description);
}

// TODO inline after merge to master
default void displayThen() {
then();
}

// TODO inline after merge to master
default void displayThen(String description) {
then(description);
}

default void displayDefaultTestFooter(ITestResult testResult) {
long testMsDuration = testResult.getEndMillis() - testResult.getStartMillis();
TestUtil.displayFooter(testResult.getMethod().getMethodName() + " FINISHED in " + testMsDuration + " ms");
}
}

0 comments on commit 1b2a4f0

Please sign in to comment.