I'm trying to create a junit Runner that will group together common tests using the junit API:
package whatever;
import org.junit.runner.Description;
import org.junit.runner.Runner;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunNotifier;
public class SomeTestRunner extends Runner {
public SomeTestRunner(Class<?> testClass) {}
#Override
public Description getDescription() {
return Description.EMPTY;
}
#Override
public void run(RunNotifier notifier) {
for (int i = 0; i < 3; i++) {
Description parent = Description.createSuiteDescription("Parent_" + i);
for (int j = 0; j < 3; j++) {
Description child = Description.createTestDescription(Exception.class, "Child_" + j);
parent.addChild(child);
Failure failure = new Failure(child, new Exception());
notifier.fireTestFailure(failure);
}
Failure failure = new Failure(parent, new Exception());
notifier.fireTestFailure(failure);
}
}
}
The problem is, when I run a test using this Runner, I can see the failures in a row, both parents and children, instead of grouped together:
Results :
Tests in error:
Child_0(java.lang.Exception)
Child_1(java.lang.Exception)
Child_2(java.lang.Exception)
Parent_0
Child_0(java.lang.Exception)
Child_1(java.lang.Exception)
Child_2(java.lang.Exception)
Parent_1
Child_0(java.lang.Exception)
Child_1(java.lang.Exception)
Child_2(java.lang.Exception)
Parent_2
Tests run: 12, Failures: 0, Errors: 12, Skipped: 0
Also, I expected to see them grouped together when I run this test in Eclipse - but thats not the case. What am I missing? Is it even possible?
You can use a JUnit Test Suite, just like this:
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
#RunWith(Suite.class)
#SuiteClasses({ SomeTest.class, AnotherTest.class, YetAnotherTest.class })
public class AllTests {
}
The template to follow is Parameterized, because it seems to do what you want. For a given test class it runs the test methods multiple times, it creates a Runner for each set of parameters, which is what I think you want:
public class GroupedTestRunner extends Suite {
private class TestClassRunnerForParameters extends BlockJUnit4ClassRunner {
private String name;
TestClassRunnerForParameters(Class<?> type, String name) throws InitializationError {
super(type);
this.name = name;
}
#Override
public Object createTest() throws Exception {
return getTestClass().getOnlyConstructor().newInstance();
}
#Override
protected String getName() {
return String.format("[%s]", name);
}
#Override
protected String testName(final FrameworkMethod method) {
return String.format("%s[%s]", method.getName(), name);
}
}
private final ArrayList<Runner> runners = new ArrayList<Runner>();
public GroupedTestRunner(Class<?> klass) throws Throwable {
super(klass, Collections.<Runner> emptyList());
// do grouping things here
runners.add(new TestClassRunnerForParameters(getTestClass().getJavaClass(), "group1"));
runners.add(new TestClassRunnerForParameters(getTestClass().getJavaClass(), "group2"));
}
#Override
protected List<Runner> getChildren() {
return runners;
}
}
This produces output like (in Eclipse):
Related
In the Testcontainers documentation, there is an example for having the docker image to be parameterized with #ParameterizedTest.
This was a junit4 example.
https://github.com/testcontainers/testcontainers-java/blob/main/core/src/test/java/org/testcontainers/junit/ParameterizedDockerfileContainerTest.java
#RunWith(Parameterized.class)
public class ParameterizedDockerfileContainerTest {
private final String expectedVersion;
#Rule
public GenericContainer container;
public ParameterizedDockerfileContainerTest(String baseImage, String expectedVersion) {
container =
new GenericContainer(
new ImageFromDockerfile()
.withDockerfileFromBuilder(builder -> {
builder
.from(baseImage)
// Could potentially customise the image here, e.g. adding files, running
// commands, etc.
.build();
})
)
.withCommand("top");
this.expectedVersion = expectedVersion;
}
#Parameterized.Parameters(name = "{0}")
public static Object[][] data() {
return new Object[][] { //
{ "alpine:3.12", "3.12" },
{ "alpine:3.13", "3.13" },
{ "alpine:3.14", "3.14" },
{ "alpine:3.15", "3.15" },
{ "alpine:3.16", "3.16" },
};
}
#Test
public void simpleTest() throws Exception {
final String release = container.execInContainer("cat", "/etc/alpine-release").getStdout();
assertThat(release).as("/etc/alpine-release starts with " + expectedVersion).startsWith(expectedVersion);
}
}
I couldn't find a way to do something similar with junit5, basically :
having the container only started once for all the #ParameterizedTest methods in the class
Ofc, with a lot of if/else, playing with beforeEach, TestInfo, ... is possible but I feel like something is wrong and I'm sure the following question has probably should be answered with junit5
How to use parameterized tests for testing with multiple database versions
So, it seems the equivalent to junit5 is not possible, related to this opened issue https://github.com/junit-team/junit5/issues/878#issuecomment-546459081 as mentioned by Eddù above
With the great help of Michael Simons, I could manage to do something that works
Base class :
#Testcontainers(disabledWithoutDocker = true)
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
public abstract class MultipleNeo4jVersionsTest {
protected static String HEAP_SIZE = "256M";
public static Stream<String> neo4jVersions() {
return Stream.of("4.4.14", "5.2.0");
}
protected static String heapSizeSetting(Neo4jVersion version) {
return version.equals(Neo4jVersion.V4_4)
? "NEO4J_dbms_memory_heap_max__size"
: "NEO4J_server_memory_heap_max__size"
;
}
protected Neo4jContainer<?> getNeo4j(String version) {
var imageName = String.format("neo4j:%s-enterprise", version);
Neo4jVersion neo4jVersion = Neo4jVersion.of(version);
Neo4jContainer<?> container = new Neo4jContainer<>(imageName)
.withoutAuthentication()
.withEnv("NEO4J_ACCEPT_LICENSE_AGREEMENT", "yes")
.withEnv(heapSizeSetting(neo4jVersion), HEAP_SIZE)
.withReuse(true);
container.start();
return container;
}
}
And the actual test class
#ParameterizedTest
#MethodSource("neo4jVersions")
void loading_config(String version) throws Exception {
Neo4jContainer<?> neo4j = getNeo4j(version);
// do something here
}
Couple of useful links
https://foojay.io/today/faster-integration-tests-with-reusable-testcontainers/
https://github.com/michael-simons/neo4j-migrations/blob/main/neo4j-migrations-core/src/test/java/ac/simons/neo4j/migrations/core/CatalogBasedMigrationIT.java
https://github.com/michael-simons/neo4j-migrations/blob/main/neo4j-migrations-core/src/test/java/ac/simons/neo4j/migrations/core/TestBase.java#L49
Devopology Test Engine (Junit5 based) supports parameterized class testing. (I'm the author)
https://github.com/devopology/test-engine
Your example...
package test.neo4j;
import org.devopology.test.engine.api.AfterAll;
import org.devopology.test.engine.api.BeforeAll;
import org.devopology.test.engine.api.Parameter;
import org.devopology.test.engine.api.Test;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.containers.wait.strategy.Wait;
import java.util.ArrayList;
import java.util.Collection;
public class Neo4jTest {
#Parameter
public String dockerImageName;
#Parameter.Supplier
public static Collection<String> dockerImageNames() {
Collection<String> dockerImageNames = new ArrayList<>();
dockerImageNames.add("neo4j:4.4.14-enterprise");
dockerImageNames.add("neo4j:5.2.0-enterprise");
return dockerImageNames;
}
private Neo4jContainer<?> neo4jContainer;
#BeforeAll
public void beforeAll() {
neo4jContainer = new Neo4jContainer<>(dockerImageName)
.waitingFor(Wait.forLogMessage(".*Started..*", 1))
.withEnv("NEO4J_ACCEPT_LICENSE_AGREEMENT", "yes")
.withEnv(heapSizeSetting(dockerImageName), "256M")
.withLogConsumer(outputFrame -> System.out.print(outputFrame.getUtf8String()))
.withoutAuthentication();
neo4jContainer.start();
}
#Test
public void test1() {
System.out.println("test1 : dockerImageName = [" + dockerImageName + "]");
// do something here
}
#Test
public void test2() {
System.out.println("test2 : dockerImageName = [" + dockerImageName + "]");
// do something here
}
#AfterAll
public void afterAll() {
if (neo4jContainer != null) {
try {
neo4jContainer.close();
} catch (Throwable t) {
// DO NOTHING
}
neo4jContainer = null;
}
}
protected static String heapSizeSetting(String dockerImageName) {
return dockerImageName.contains("4.4")
? "NEO4J_dbms_memory_heap_max__size" : "NEO4J_server_memory_heap_max__size";
}
}
I added a Builder pattern to several complex classes and when I ran coverage on my tests, all of the classes that use the Builder pattern now report that there is an uncovered class in the testing.
Here is a simplified example:
public class CoverageWithBuilder {
public int fInt;
public static class Builder {
public Integer fInteger = null;
public Builder setInt(int i) {
fInteger = i;
return this;
}
public CoverageWithBuilder build() {
if (fInteger == null)
throw new IllegalStateException("Oops");
return new CoverageWithBuilder(fInteger);
}
}
private CoverageWithBuilder(int i) {
fInt = i;
}
public int getInt() {
return fInt;
}
}
And here's the test:
import org.junit.Test;
import static org.junit.Assert.*;
public class CoverageWithBuilderTest {
#Test
public void test1() {
CoverageWithBuilder t = new CoverageWithBuilder.Builder().setInt(9).build();
assertEquals(9, t.getInt());
}
#Test(expected = IllegalStateException.class)
public void test2() {
new CoverageWithBuilder.Builder().build();
}
}
Coverage (using IntelliJ Idea with any of the coverage tool options - IntelliJ, Emma, JaCoCo) reports only partial class coverage:
CoverageWithBuilder .... 66% (2/3) . 100% (6/6) . 100% (12/12)
What is this third class of which the coverage tools speak?
I a quite new to Junit. I have a question on how Java runs Junit classes. I have a code like this
public class TestJunit1 {
String message = "Srinivas";
MessageUtil messageutil = new MessageUtil(message);
#Test
public void testPrintMessage() {
System.out.println("Inside testPrintMessage");
assertEquals(message, messageutil.printMessage());
}
}
public class TestJUnit5 extends TestCase {
protected double fValue1;
protected double fValue2;
#Before
public void setUp() throws Exception {
fValue1 = 2.0;
fValue2 = 3.0;
}
#Test
public void testAdding() {
System.out.println("No of test cases =" + this.countTestCases());
String name = this.getName();
System.out.println("Test Case name is: "+name);
this.setName("methodNewAdd");
String newName = this.getName();
System.out.println("New name of the test case is:"+newName);
System.out.println(this.getClass());
}
#After
public void tearDown() throws Exception {
}
public class TestSuiteDemo {
public static void main(String[] args) {
TestSuite ts = new TestSuite(TestJunit1.class, TestJunit2.class, TestJUnit5.class);
TestResult tr = new TestResult();
ts.run(tr);
System.out.println("Number of test cases is:"+tr.runCount());
}
}
when I run TestSuiteDemo as Java application in eclipse, it produces output from println statements from TestJUnit5 and not from TestJunit1.
Could somebody please explain why this happens?
Regards
Srinivas
Because TestJUnit5 extends a TestCase (not TestJunit1) so JUnit sees the test case and runs it.
From the junit.framework.TestSuite code, any class that inherits Test class or extends TestCase can get registered with TestSuite constructor.
private void addTestsFromTestCase(final Class<?> theClass) {
fName = theClass.getName();
try {
getTestConstructor(theClass); // Avoid generating multiple error messages
} catch (NoSuchMethodException e) {
addTest(warning("Class " + theClass.getName() + " has no public constructor TestCase(String name) or TestCase()"));
return;
}
if (!Modifier.isPublic(theClass.getModifiers())) {
addTest(warning("Class " + theClass.getName() + " is not public"));
return;
}
Class<?> superClass = theClass;
List<String> names = new ArrayList<String>();
while (Test.class.isAssignableFrom(superClass)) {
for (Method each : MethodSorter.getDeclaredMethods(superClass)) {
addTestMethod(each, names, theClass);
}
superClass = superClass.getSuperclass();
}
if (fTests.size() == 0) {
addTest(warning("No tests found in " + theClass.getName()));
}
}
To get TestJunit1 to work, you will have to create an annotative Suite.
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
#RunWith(Suite.class)
#Suite.SuiteClasses({
TestJunit1.class,
TestJunit2.class,
TestJunit5.class
})
public class JunitTestSuite {
}
And to run it locally:
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;
public class JunitTestSuiteRunner {
public static void main(String[] args) {
Result result = JUnitCore.runClasses(JunitTestSuite.class);
for (Failure fail : result.getFailures()) {
System.out.println(fail.toString());
}
if (result.wasSuccessful()) {
System.out.println("All tests finished successfully...");
}
}
}
I hope this helps.
Source reference.
amoq reference to the stackoverflow post JUnit confusion: use 'extends TestCase' or '#Test'?
is accurate. There are two main way for junit test to recognize and run your rest Junit version 3 , extend test case . Junit version 4 annotate with #Test.
Since your test 1 has neither it is not run at all. Confirm the version of junit your eclipse is using, you could use the annotation version #Test which u might find more pleasant
In junit4 I want to execute specific test methods from different classes i.e want create a test suite with specific test methods from different classes.
Lets say I have 2 classes:
public class Test_Login {
#Test
public void test_Login_001(){
System.out.println("test_Login_001");
}
#Test
public void test_Login_002(){
System.out.println("test_Login_002");
}
#Test
public void test_Login_003(){
System.out.println("test_Login_003");
}
}
public class Logout {
#Test
public void test_Logout_001(){
System.out.println("test_Logout_001");
}
#Test
public void test_Logout_002(){
System.out.println("test_Logout_002");
}
#Test
public void test_Logout_003(){
System.out.println("test_Logout_003");
}
}
From the above classes I want to execute test methods test_Login_001 , test_Login_003 , test_Logout_002 only.
How this can be achieved in junit4 ?
Since JUnit 4.8 introduced Categories there exists a clean solution, create a TestSuite:
#RunWith(Categories.class)
#IncludeCategory(MustHaveTests.class)
#SuiteClasses( { Test_Login.class, Test_Logout.class })
public class MustHaveTestsTestSuite {
public interface MustHaveTests { /* category marker */ }
}
And add the #Category(MustHaveTests.class) above every test you would like to run with the TestSuite, e.g.:
#Category(MustHaveTests.class)
#Test
public void test_Login_001(){
System.out.println("test_Login_001");
}
When running the TestSuite only the MustHaveTests-"tagged" tests will be executed. More Details on #Category: https://github.com/junit-team/junit4/wiki/categories
You need to create an org.junit.runner.Request and pass it to the JunitCore runner, or actually to any Runner.
JUnitCore junitRunner = new JUnitCore();
Request request = Request.method(Logout.class, "test_Logout_002");
Result result = junitRunner.run(request);
I actually created an Annotation and can search for methods with those annotations and dynamically create Request and run them
public class TestsSuite {
public static void main(String[] args) throws Exception {
Class annotation = MyTestAnnotation.class;
JUnitCore junitRunner = new JUnitCore();
Class testClass = Test_Login.class;
Method[] methods = testClass.getMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(annotation)) {
if (method.isAnnotationPresent(org.junit.Test.class)) {
Request request = Request.method(testClass, method.getName());
Result result = junitRunner.run(request);
System.out.println(result.wasSuccessful());
}
}
}
}
}
This might not be the slickest implementation, but I solved a similar problem by created a new #SuiteMethods annotation as follows:
SuiteMethods.java
#Retention(RUNTIME)
#Target(TYPE)
public #interface SuiteMethods {
String[] value() default {""};
}
FilteredSuite.java
public class FilteredSuite extends Categories {
private static String[] TEST_METHODS_TO_RUN = {""}; // default behavior is to run all methods
private static Class<?> extractMethodNamesFromAnnotation(Class<?> clazz) {
SuiteMethods methodsAnnotation = clazz.getAnnotation(SuiteMethods.class);
if (methodsAnnotation != null) {
// if our MethodsAnnotation was specified, use it's value as our methods filter
TEST_METHODS_TO_RUN = methodsAnnotation.value();
}
return clazz;
}
public static Filter getCustomFilter() {
Filter f = new Filter() {
#Override
public boolean shouldRun(Description desc) {
String methodName = desc.getMethodName();
for (String subString : TEST_METHODS_TO_RUN) {
if (methodName == null || methodName.contains(subString)) {
return true;
}
}
return false;
}
#Override
public String describe() {
return null;
}
};
return f;
}
public FilteredSuite(Class<?> arg0, RunnerBuilder arg1) throws InitializationError {
super(extractMethodNamesFromAnnotation(arg0), arg1);
}
#Override
public void filter(Filter arg0) throws NoTestsRemainException {
// At test suite startup, JUnit framework calls this method to install CategoryFilter.
// Throw away the given filter and install our own method name filter
super.filter(getCustomFilter());
}
}
A Usage Example
#RunWith(FilteredSuite.class)
#SuiteClasses({
GroupRestTest.class,
ScenarioRestTest.class
})
#SuiteMethods({
"testReadOnlyFlag",
"testSheetWriteData",
"testAddScenarioMeta"
})
public class SubsetTestSuite {
}
I have a JUnit 3.x TestCase which I would like to be able to parameterize. I'd like to parametrize the entire TestCase (including the fixture). However, the TestSuite.addTestSuite() method does not allow be to pass a TestCase object, just a class:
TestSuite suite = new TestSuite("suite");
suite.addTestSuite(MyTestCase.class);
I would like to be able to pass a parameter (a string) to the MyTestCase instance which is created when the test runs. As it is now, I have to have a separate class for each parameter value.
I tried passing it an anynomous subclass:
MyTestCase testCase = new MyTestCase() {
String getOption() {
return "some value";
}
}
suite.addTestSuite(testCase.getClass());
However, this fails with the assertion:
... MyTestSuite$1 has no public constructor TestCase(String name) or TestCase()`
Any ideas? Am I attacking the problem the wrong way?
If this is Java 5 or higher, you might want to consider switching to JUnit 4, which has support for parameterized test cases built in.
Rather than create a parameterized test case for the multiple/different backends you want to test against, I would look into making my test cases abstract. Each new implementation of your API would need to supply an implementing TestCase class.
If you currently have a test method that looks something like
public void testSomething() {
API myAPI = new BlahAPI();
assertNotNull(myAPI.something());
}
just add an abstract method to the TestCase that returns the specific API object to use.
public abstract class AbstractTestCase extends TestCase {
public abstract API getAPIToTest();
public void testSomething() {
API myAPI = getAPIToTest();
assertNotNull(myAPI.something());
}
public void testSomethingElse() {
API myAPI = getAPIToTest();
assertNotNull(myAPI.somethingElse());
}
}
Then the TestCase for the new implementation you want to test only has to implement your AbstractTestCase and supply the concrete implementation of the API class:
public class ImplementationXTestCase extends AbstractTestCase{
public API getAPIToTest() {
return new ImplementationX();
}
}
Then all of the test methods that test the API in the abstract class are run automatically.
Ok, here is a quick mock-up of how JUnit 4 runs parameterized tests, but done in JUnit 3.8.2.
Basically I'm subclassing and badly hijacking the TestSuite class to populate the list of tests according to the cross-product of testMethods and parameters.
Unfortunately I've had to copy a couple of helper methods from TestSuite itself, and a few details are not perfect, such as the names of the tests in the IDE being the same across parameter sets (JUnit 4.x appends [0], [1], ...).
Nevertheless, this seems to run fine in the text and AWT TestRunners that ship with JUnit as well as in Eclipse.
Here is the ParameterizedTestSuite, and further down a (silly) example of a parameterized test using it.
(final note : I've written this with Java 5 in mind, it should be trivial to adapt to 1.4 if needed)
ParameterizedTestSuite.java:
package junit.parameterized;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
public class ParameterizedTestSuite extends TestSuite {
public ParameterizedTestSuite(
final Class<? extends TestCase> testCaseClass,
final Collection<Object[]> parameters) {
setName(testCaseClass.getName());
final Constructor<?>[] constructors = testCaseClass.getConstructors();
if (constructors.length != 1) {
addTest(warning(testCaseClass.getName()
+ " must have a single public constructor."));
return;
}
final Collection<String> names = getTestMethods(testCaseClass);
final Constructor<?> constructor = constructors[0];
final Collection<TestCase> testCaseInstances = new ArrayList<TestCase>();
try {
for (final Object[] objects : parameters) {
for (final String name : names) {
TestCase testCase = (TestCase) constructor.newInstance(objects);
testCase.setName(name);
testCaseInstances.add(testCase);
}
}
} catch (IllegalArgumentException e) {
addConstructionException(e);
return;
} catch (InstantiationException e) {
addConstructionException(e);
return;
} catch (IllegalAccessException e) {
addConstructionException(e);
return;
} catch (InvocationTargetException e) {
addConstructionException(e);
return;
}
for (final TestCase testCase : testCaseInstances) {
addTest(testCase);
}
}
private Collection<String> getTestMethods(
final Class<? extends TestCase> testCaseClass) {
Class<?> superClass= testCaseClass;
final Collection<String> names= new ArrayList<String>();
while (Test.class.isAssignableFrom(superClass)) {
Method[] methods= superClass.getDeclaredMethods();
for (int i= 0; i < methods.length; i++) {
addTestMethod(methods[i], names, testCaseClass);
}
superClass = superClass.getSuperclass();
}
return names;
}
private void addTestMethod(Method m, Collection<String> names, Class<?> theClass) {
String name= m.getName();
if (names.contains(name))
return;
if (! isPublicTestMethod(m)) {
if (isTestMethod(m))
addTest(warning("Test method isn't public: "+m.getName()));
return;
}
names.add(name);
}
private boolean isPublicTestMethod(Method m) {
return isTestMethod(m) && Modifier.isPublic(m.getModifiers());
}
private boolean isTestMethod(Method m) {
String name= m.getName();
Class<?>[] parameters= m.getParameterTypes();
Class<?> returnType= m.getReturnType();
return parameters.length == 0 && name.startsWith("test") && returnType.equals(Void.TYPE);
}
private void addConstructionException(Exception e) {
addTest(warning("Instantiation of a testCase failed "
+ e.getClass().getName() + " " + e.getMessage()));
}
}
ParameterizedTest.java:
package junit.parameterized;
import java.util.Arrays;
import java.util.Collection;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.parameterized.ParameterizedTestSuite;
public class ParameterizedTest extends TestCase {
private final int value;
private int evilState;
public static Collection<Object[]> parameters() {
return Arrays.asList(
new Object[] { 1 },
new Object[] { 2 },
new Object[] { -2 }
);
}
public ParameterizedTest(final int value) {
this.value = value;
}
public void testMathPow() {
final int square = value * value;
final int powSquare = (int) Math.pow(value, 2) + evilState;
assertEquals(square, powSquare);
evilState++;
}
public void testIntDiv() {
final int div = value / value;
assertEquals(1, div);
}
public static Test suite() {
return new ParameterizedTestSuite(ParameterizedTest.class, parameters());
}
}
Note: the evilState variable is just here to show that all test instances are different as they should be, and that there is no shared state between them.
a few details are not perfect, such as the names of the tests in the IDE being the same across parameter sets (JUnit 4.x appends [0], [1], ...).
To solve this you just need to overwrite getName() and change the constructor in your test case class:
private String displayName;
public ParameterizedTest(final int value) {
this.value = value;
this.displayName = Integer.toString(value);
}
#Override
public String getName() {
return super.getName() + "[" + displayName + "]";
}
For Android projects, we wrote a library called Burst for test parameterization. For example
public class ParameterizedTest extends TestCase {
enum Drink { COKE, PEPSI, RC_COLA }
private final Drink drink;
// Nullary constructor required by Android test framework
public ConstructorTest() {
this(null);
}
public ConstructorTest(Drink drink) {
this.drink = drink;
}
public void testSomething() {
assertNotNull(drink);
}
}
Not really an answer to your question since you're not using Android, but a lot of projects which still use JUnit 3 do so because Android's test framework requires it, so I hope some other readers will find this helpful.