mirror of
https://github.com/google/nomulus.git
synced 2025-04-30 12:07:51 +02:00
Make AppEngineRule work with JUnit 5 (#548)
* Make AppEngineRule work with JUnit 5 Made AppEngineRule work with both JUnit4 and JUnit 5 and applied it to PremiumListTest. Next step is to convert SqlIntegrationTestSuite.java to JUnit5.
This commit is contained in:
parent
2f6ba8cc29
commit
3dbc4e5d46
4 changed files with 97 additions and 15 deletions
|
@ -29,16 +29,14 @@ import google.registry.model.registry.label.PremiumList.PremiumListEntry;
|
||||||
import google.registry.model.registry.label.PremiumList.PremiumListRevision;
|
import google.registry.model.registry.label.PremiumList.PremiumListRevision;
|
||||||
import google.registry.testing.AppEngineRule;
|
import google.registry.testing.AppEngineRule;
|
||||||
import org.joda.money.Money;
|
import org.joda.money.Money;
|
||||||
import org.junit.Rule;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.migrationsupport.rules.EnableRuleMigrationSupport;
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
|
|
||||||
/** Unit tests for {@link PremiumList}. */
|
/** Unit tests for {@link PremiumList}. */
|
||||||
@EnableRuleMigrationSupport
|
|
||||||
public class PremiumListTest {
|
public class PremiumListTest {
|
||||||
|
|
||||||
@Rule
|
@RegisterExtension
|
||||||
public final AppEngineRule appEngine = AppEngineRule.builder().withDatastoreAndCloudSql().build();
|
public final AppEngineRule appEngine = AppEngineRule.builder().withDatastoreAndCloudSql().build();
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
|
|
|
@ -27,6 +27,7 @@ import java.sql.SQLException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Supplier;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
import org.junit.rules.ExternalResource;
|
import org.junit.rules.ExternalResource;
|
||||||
|
|
||||||
|
@ -51,15 +52,15 @@ public class JpaEntityCoverage extends ExternalResource {
|
||||||
private static final Map<String, Boolean> testsJpaEntities = Maps.newHashMap();
|
private static final Map<String, Boolean> testsJpaEntities = Maps.newHashMap();
|
||||||
|
|
||||||
// Provides class name of the test being executed.
|
// Provides class name of the test being executed.
|
||||||
private final TestCaseWatcher watcher;
|
private final Supplier<String> currTestClassNameSupplier;
|
||||||
|
|
||||||
public JpaEntityCoverage(TestCaseWatcher watcher) {
|
public JpaEntityCoverage(Supplier<String> currTestClassNameSupplier) {
|
||||||
this.watcher = watcher;
|
this.currTestClassNameSupplier = currTestClassNameSupplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void before() {
|
public void before() {
|
||||||
testsJpaEntities.putIfAbsent(watcher.getTestClass(), false);
|
testsJpaEntities.putIfAbsent(currTestClassNameSupplier.get(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -69,7 +70,7 @@ public class JpaEntityCoverage extends ExternalResource {
|
||||||
.forEach(
|
.forEach(
|
||||||
entity -> {
|
entity -> {
|
||||||
allCoveredJpaEntities.add(entity);
|
allCoveredJpaEntities.add(entity);
|
||||||
testsJpaEntities.put(watcher.getTestClass(), true);
|
testsJpaEntities.put(currTestClassNameSupplier.get(), true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,9 @@ import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
|
import org.junit.jupiter.api.extension.AfterEachCallback;
|
||||||
|
import org.junit.jupiter.api.extension.BeforeEachCallback;
|
||||||
|
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||||
import org.junit.rules.RuleChain;
|
import org.junit.rules.RuleChain;
|
||||||
import org.junit.rules.TestRule;
|
import org.junit.rules.TestRule;
|
||||||
import org.junit.runner.Description;
|
import org.junit.runner.Description;
|
||||||
|
@ -88,7 +91,7 @@ public class JpaTestRules {
|
||||||
this.ruleChain =
|
this.ruleChain =
|
||||||
RuleChain.outerRule(watcher)
|
RuleChain.outerRule(watcher)
|
||||||
.around(integrationTestRule)
|
.around(integrationTestRule)
|
||||||
.around(new JpaEntityCoverage(watcher));
|
.around(new JpaEntityCoverage(watcher::getTestClass));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -97,6 +100,40 @@ public class JpaTestRules {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JUnit extension for member classes of {@link
|
||||||
|
* google.registry.schema.integration.SqlIntegrationTestSuite}. In addition to providing a
|
||||||
|
* database through {@link JpaIntegrationTestRule}, it also keeps track of the test coverage of
|
||||||
|
* the declared JPA entities (in persistence.xml). Per-class statistics are stored in static
|
||||||
|
* variables. The SqlIntegrationTestSuite inspects the cumulative statistics after all test
|
||||||
|
* classes have run.
|
||||||
|
*/
|
||||||
|
public static final class JpaIntegrationWithCoverageExtension
|
||||||
|
implements BeforeEachCallback, AfterEachCallback {
|
||||||
|
private String currentTestClassName = null;
|
||||||
|
private final JpaEntityCoverage jpaEntityCoverage =
|
||||||
|
new JpaEntityCoverage(() -> this.currentTestClassName);
|
||||||
|
private final JpaIntegrationTestRule integrationTestRule;
|
||||||
|
|
||||||
|
JpaIntegrationWithCoverageExtension(JpaIntegrationTestRule integrationTestRule) {
|
||||||
|
this.integrationTestRule = integrationTestRule;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeEach(ExtensionContext context) throws Exception {
|
||||||
|
this.currentTestClassName = context.getRequiredTestClass().getName();
|
||||||
|
integrationTestRule.before();
|
||||||
|
jpaEntityCoverage.before();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterEach(ExtensionContext context) throws Exception {
|
||||||
|
jpaEntityCoverage.after();
|
||||||
|
integrationTestRule.after();
|
||||||
|
this.currentTestClassName = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Builder of test rules that provide {@link JpaTransactionManager}. */
|
/** Builder of test rules that provide {@link JpaTransactionManager}. */
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
private String initScript;
|
private String initScript;
|
||||||
|
@ -149,6 +186,15 @@ public class JpaTestRules {
|
||||||
return new JpaIntegrationWithCoverageRule(buildIntegrationTestRule());
|
return new JpaIntegrationWithCoverageRule(buildIntegrationTestRule());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JUnit extension that adapts {@link JpaIntegrationTestRule} for JUnit 5 and also checks test
|
||||||
|
* coverage of JPA entity classes.
|
||||||
|
*/
|
||||||
|
public JpaIntegrationWithCoverageExtension buildIntegrationWithCoverageExtension() {
|
||||||
|
checkState(initScript == null, "Integration tests do not accept initScript");
|
||||||
|
return new JpaIntegrationWithCoverageExtension(buildIntegrationTestRule());
|
||||||
|
}
|
||||||
|
|
||||||
/** Builds a {@link JpaUnitTestRule} instance. */
|
/** Builds a {@link JpaUnitTestRule} instance. */
|
||||||
public JpaUnitTestRule buildUnitTestRule() {
|
public JpaUnitTestRule buildUnitTestRule() {
|
||||||
checkState(
|
checkState(
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
package google.registry.testing;
|
package google.registry.testing;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkState;
|
||||||
import static com.google.common.truth.Truth.assertWithMessage;
|
import static com.google.common.truth.Truth.assertWithMessage;
|
||||||
import static google.registry.testing.DatastoreHelper.persistSimpleResources;
|
import static google.registry.testing.DatastoreHelper.persistSimpleResources;
|
||||||
import static google.registry.util.ResourceUtils.readResourceUtf8;
|
import static google.registry.util.ResourceUtils.readResourceUtf8;
|
||||||
|
@ -40,6 +41,7 @@ import google.registry.model.registrar.Registrar.State;
|
||||||
import google.registry.model.registrar.RegistrarAddress;
|
import google.registry.model.registrar.RegistrarAddress;
|
||||||
import google.registry.model.registrar.RegistrarContact;
|
import google.registry.model.registrar.RegistrarContact;
|
||||||
import google.registry.persistence.transaction.JpaTestRules;
|
import google.registry.persistence.transaction.JpaTestRules;
|
||||||
|
import google.registry.persistence.transaction.JpaTestRules.JpaIntegrationWithCoverageExtension;
|
||||||
import google.registry.persistence.transaction.JpaTestRules.JpaIntegrationWithCoverageRule;
|
import google.registry.persistence.transaction.JpaTestRules.JpaIntegrationWithCoverageRule;
|
||||||
import google.registry.util.Clock;
|
import google.registry.util.Clock;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
@ -53,6 +55,9 @@ import javax.annotation.Nullable;
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
import org.junit.jupiter.api.extension.AfterEachCallback;
|
||||||
|
import org.junit.jupiter.api.extension.BeforeEachCallback;
|
||||||
|
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||||
import org.junit.rules.ExternalResource;
|
import org.junit.rules.ExternalResource;
|
||||||
import org.junit.rules.TemporaryFolder;
|
import org.junit.rules.TemporaryFolder;
|
||||||
import org.junit.runner.Description;
|
import org.junit.runner.Description;
|
||||||
|
@ -66,9 +71,15 @@ import org.junit.runners.model.Statement;
|
||||||
*
|
*
|
||||||
* <p>This rule also resets global Objectify for the current thread.
|
* <p>This rule also resets global Objectify for the current thread.
|
||||||
*
|
*
|
||||||
|
* <p>This class works with both JUnit 4 and JUnit 5. With JUnit 4, the test runner calls {@link
|
||||||
|
* #apply(Statement, Description)}, which in turns calls {@link #before()} on entry and {@link
|
||||||
|
* #after()} on exit. With JUnit 5, the test runner calls {@link #beforeEach(ExtensionContext)} and
|
||||||
|
* {@link #afterEach(ExtensionContext)}.
|
||||||
|
*
|
||||||
* @see org.junit.rules.ExternalResource
|
* @see org.junit.rules.ExternalResource
|
||||||
*/
|
*/
|
||||||
public final class AppEngineRule extends ExternalResource {
|
public final class AppEngineRule extends ExternalResource
|
||||||
|
implements BeforeEachCallback, AfterEachCallback {
|
||||||
|
|
||||||
public static final String NEW_REGISTRAR_GAE_USER_ID = "666";
|
public static final String NEW_REGISTRAR_GAE_USER_ID = "666";
|
||||||
public static final String THE_REGISTRAR_GAE_USER_ID = "31337";
|
public static final String THE_REGISTRAR_GAE_USER_ID = "31337";
|
||||||
|
@ -93,6 +104,8 @@ public final class AppEngineRule extends ExternalResource {
|
||||||
|
|
||||||
/** A rule-within-a-rule to provide a temporary folder for AppEngineRule's internal temp files. */
|
/** A rule-within-a-rule to provide a temporary folder for AppEngineRule's internal temp files. */
|
||||||
TemporaryFolder temporaryFolder = new TemporaryFolder();
|
TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||||
|
// Sets up a SQL database when running on JUnit 5.
|
||||||
|
JpaIntegrationWithCoverageExtension jpaIntegrationWithCoverageExtension = null;
|
||||||
|
|
||||||
private boolean withDatastoreAndCloudSql;
|
private boolean withDatastoreAndCloudSql;
|
||||||
private boolean withLocalModules;
|
private boolean withLocalModules;
|
||||||
|
@ -257,14 +270,38 @@ public final class AppEngineRule extends ExternalResource {
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Called before every test method. JUnit 5 only. */
|
||||||
|
@Override
|
||||||
|
public void beforeEach(ExtensionContext context) throws Exception {
|
||||||
|
before();
|
||||||
|
if (withDatastoreAndCloudSql) {
|
||||||
|
JpaTestRules.Builder builder = new JpaTestRules.Builder();
|
||||||
|
if (clock != null) {
|
||||||
|
builder.withClock(clock);
|
||||||
|
}
|
||||||
|
jpaIntegrationWithCoverageExtension = builder.buildIntegrationWithCoverageExtension();
|
||||||
|
jpaIntegrationWithCoverageExtension.beforeEach(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Called after each test method. JUnit 5 only. */
|
||||||
|
@Override
|
||||||
|
public void afterEach(ExtensionContext context) throws Exception {
|
||||||
|
if (withDatastoreAndCloudSql) {
|
||||||
|
checkState(
|
||||||
|
jpaIntegrationWithCoverageExtension != null, "Null jpaIntegrationWithCoverageExtension");
|
||||||
|
jpaIntegrationWithCoverageExtension.afterEach(context);
|
||||||
|
}
|
||||||
|
after();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hack to make sure AppEngineRule is always wrapped in a {@link JpaIntegrationWithCoverageRule}.
|
* Hack to make sure AppEngineRule is always wrapped in a {@link JpaIntegrationWithCoverageRule}.
|
||||||
|
* JUnit 4 only.
|
||||||
*/
|
*/
|
||||||
// Note: Even with @EnableRuleMigrationSupport, JUnit5 runner does not call this method.
|
// Note: Even with @EnableRuleMigrationSupport, JUnit5 runner does not call this method.
|
||||||
// Note 2: Do not migrate any members of SqlIntegrationTestSuite to JUnit5 before
|
// Note 2: Do not migrate members of SqlIntegrationTestSuite to JUnit5 individually.
|
||||||
// calls to JpaIntegrationWithCoverageRule can be made elsewhere.
|
// TODO(weiminyu): migrate SqlIntegrationTestSuite in one go.
|
||||||
// TODO(weiminyu): make JpaIntegrationWithCoverageRule implement ExternaResource and invoke it in
|
|
||||||
// before() and after(), then drop this method.
|
|
||||||
@Override
|
@Override
|
||||||
public Statement apply(Statement base, Description description) {
|
public Statement apply(Statement base, Description description) {
|
||||||
Statement statement = base;
|
Statement statement = base;
|
||||||
|
|
Loading…
Add table
Reference in a new issue