Skip to content

Commit 4858929

Browse files
authored
Merge pull request #411 from yuuki3655/orchestrator_with_coverage_example
Add an example project that demonstrates how to use Jacoco test cover…
2 parents 66a9896 + 2cb1bbd commit 4858929

File tree

26 files changed

+1038
-0
lines changed

26 files changed

+1038
-0
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.gradle
2+
/local.properties
3+
.idea
4+
*.iml
5+
.DS_Store
6+
build
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# AndroidTestOrchestrator with test coverage sample
2+
3+
The Android Test Orchestrator allows you to run each of your app's tests in isolation, enabling greater reliability.
4+
See https://developer.android.com/training/testing/junit-runner#using-android-test-orchestrator for more background.
5+
6+
This sample is a subset of the AndroidJUnitRunner sample, but it
7+
illustrates how to enable Jacoco test coverage report with the Android Test Orchestrator in the app/build.gradle file.
8+
9+
This project uses the Gradle build system. You don't need an IDE to build and execute it but Android Studio is recommended.
10+
11+
1. Download the project code, preferably using `git clone`.
12+
1. Open the Android SDK Manager (*Tools* Menu | *Android*).
13+
1. In Android Studio, select *File* | *Open...* and point to the top-level `./build.gradle` file.
14+
1. Check out the relevant code:
15+
* The application under test is located in `src/main/java`
16+
* Tests are in `src/androidTest/java`
17+
1. Connect a device or start an emulator:
18+
* Turn animations off.
19+
(On your device, under Settings->Developer options disable the following 3 settings: "Window animation scale", "Transition animation scale" and "Animator duration scale")
20+
1. Run the newly created configuration.
21+
22+
The application will be started on the device/emulator and a series of actions will be performed automatically.
23+
24+
If you are using Android Studio, the *Run* window will show the test results.
25+
The test coverage report will be generated in `app/build/reports/coverage/androidTest/debug/index.html`.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
apply plugin: 'com.android.application'
2+
3+
android {
4+
compileSdkVersion 31
5+
buildToolsVersion rootProject.buildToolsVersion
6+
defaultConfig {
7+
applicationId "com.example.android.testing.androidtestorchestratorsample"
8+
minSdkVersion 14
9+
targetSdkVersion 31
10+
versionCode 1
11+
versionName "1.0"
12+
13+
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
14+
testInstrumentationRunnerArguments clearPackageData: 'true'
15+
testInstrumentationRunnerArguments useTestStorageService: 'true'
16+
}
17+
buildTypes {
18+
debug {
19+
testCoverageEnabled true
20+
}
21+
}
22+
testOptions {
23+
execution 'ANDROIDX_TEST_ORCHESTRATOR'
24+
}
25+
}
26+
27+
dependencies {
28+
// App's dependencies, including test
29+
implementation 'androidx.annotation:annotation:' + rootProject.androidxAnnotationVersion
30+
implementation 'com.google.guava:guava:' + rootProject.guavaVersion
31+
32+
// Testing-only dependencies
33+
androidTestImplementation 'androidx.test:core:' + rootProject.coreVersion
34+
androidTestImplementation 'androidx.test.ext:junit:' + rootProject.extJUnitVersion
35+
androidTestImplementation 'androidx.test:runner:' + rootProject.runnerVersion
36+
androidTestImplementation 'androidx.test.espresso:espresso-core:' + rootProject.espressoVersion
37+
androidTestUtil 'androidx.test:orchestrator:' + rootProject.runnerVersion
38+
androidTestUtil 'androidx.test.services:test-services:' + rootProject.testServicesVersion
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* Copyright 2020, The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.android.testing.androidtestorchestratorsample;
18+
19+
import org.junit.Before;
20+
import org.junit.Test;
21+
import org.junit.runner.RunWith;
22+
import org.junit.runners.Parameterized;
23+
24+
import androidx.test.filters.SmallTest;
25+
26+
import java.lang.Iterable;
27+
import java.util.Arrays;
28+
29+
import static org.hamcrest.CoreMatchers.equalTo;
30+
import static org.hamcrest.CoreMatchers.is;
31+
import static org.junit.Assert.assertThat;
32+
import static org.junit.runners.Parameterized.Parameters;
33+
34+
35+
/**
36+
* JUnit4 tests for the calculator's add logic.
37+
*
38+
* <p> This test uses a Junit4s Parameterized tests features which uses annotations to pass
39+
* parameters into a unit test. The way this works is that you have to use the {@link Parameterized}
40+
* runner to run your tests.
41+
* </p>
42+
*/
43+
@RunWith(Parameterized.class)
44+
@SmallTest
45+
public class CalculatorAddParameterizedTest {
46+
47+
/**
48+
* @return {@link Iterable} that contains the values that should be passed to the constructor.
49+
* In this example we are going to use three parameters: operand one, operand two and the
50+
* expected result.
51+
*/
52+
@Parameters
53+
public static Iterable<Object[]> data() {
54+
return Arrays.asList(new Object[][]{
55+
{0, 0, 0},
56+
{0, -1, -1},
57+
{2, 2, 4},
58+
{8, 8, 16},
59+
{16, 16, 32},
60+
{32, 0, 32},
61+
{64, 64, 128}});
62+
}
63+
64+
private final double mOperandOne;
65+
private final double mOperandTwo;
66+
private final double mExpectedResult;
67+
68+
private Calculator mCalculator;
69+
70+
/**
71+
* Constructor that takes in the values specified in
72+
* {@link CalculatorAddParameterizedTest#data()}. The values need to be saved to fields in order
73+
* to reuse them in your tests.
74+
*/
75+
public CalculatorAddParameterizedTest(double operandOne, double operandTwo,
76+
double expectedResult) {
77+
78+
mOperandOne = operandOne;
79+
mOperandTwo = operandTwo;
80+
mExpectedResult = expectedResult;
81+
}
82+
83+
@Before
84+
public void setUp() {
85+
mCalculator = new Calculator();
86+
}
87+
88+
@Test
89+
public void testAdd_TwoNumbers() {
90+
double resultAdd = mCalculator.add(mOperandOne, mOperandTwo);
91+
assertThat(resultAdd, is(equalTo(mExpectedResult)));
92+
}
93+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* Copyright 2020, The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.android.testing.androidtestorchestratorsample;
18+
19+
import junit.framework.TestSuite;
20+
21+
import org.junit.Before;
22+
import org.junit.Test;
23+
import org.junit.internal.builders.AllDefaultPossibilitiesBuilder;
24+
import org.junit.runner.RunWith;
25+
26+
import androidx.test.core.app.ActivityScenario;
27+
import androidx.test.ext.junit.runners.AndroidJUnit4;
28+
import androidx.test.filters.LargeTest;
29+
import androidx.test.runner.AndroidJUnitRunner;
30+
31+
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
32+
import static androidx.test.espresso.Espresso.onView;
33+
import static androidx.test.espresso.action.ViewActions.click;
34+
import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard;
35+
import static androidx.test.espresso.action.ViewActions.typeText;
36+
import static androidx.test.espresso.assertion.ViewAssertions.matches;
37+
import static androidx.test.espresso.matcher.ViewMatchers.withId;
38+
import static androidx.test.espresso.matcher.ViewMatchers.withText;
39+
40+
/**
41+
* JUnit4 Ui Tests for {@link CalculatorActivity} using the {@link AndroidJUnitRunner} with the
42+
* Android Test Orchestrator.
43+
* This class uses the JUnit4 syntax for tests.
44+
* <p>
45+
* With the new AndroidJUnit runner you can run both JUnit3 and JUnit4 tests in a single test
46+
* suite. The {@link AndroidRunnerBuilder} which extends JUnit's
47+
* {@link AllDefaultPossibilitiesBuilder} will create a single {@link
48+
* TestSuite} from all tests and run them.
49+
*/
50+
@RunWith(AndroidJUnit4.class)
51+
@LargeTest
52+
public class CalculatorInstrumentationTest {
53+
54+
/**
55+
* Use {@link ActivityScenario} to create and launch of the activity.
56+
*/
57+
@Before
58+
public void launchActivity() {
59+
ActivityScenario.launch(CalculatorActivity.class);
60+
}
61+
62+
@Test
63+
public void noOperandShowsComputationError() {
64+
final String expectedResult = getApplicationContext().getString(R.string.computationError);
65+
onView(withId(R.id.operation_add_btn)).perform(click());
66+
onView(withId(R.id.operation_result_text_view)).check(matches(withText(expectedResult)));
67+
}
68+
69+
@Test
70+
public void typeOperandsAndPerformAddOperation() {
71+
performOperation(R.id.operation_add_btn, "16.0", "16.0", "32.0");
72+
}
73+
74+
@Test
75+
public void typeOperandsAndPerformSubOperation() {
76+
performOperation(R.id.operation_sub_btn, "32.0", "16.0", "16.0");
77+
}
78+
79+
@Test
80+
public void typeOperandsAndPerformDivOperation() {
81+
performOperation(R.id.operation_div_btn, "128.0", "16.0", "8.0");
82+
}
83+
84+
@Test
85+
public void divZeroForOperandTwoShowsError() {
86+
final String expectedResult = getApplicationContext().getString(R.string.computationError);
87+
performOperation(R.id.operation_div_btn, "128.0", "0.0", expectedResult);
88+
}
89+
90+
@Test
91+
public void typeOperandsAndPerformMulOperation() {
92+
performOperation(R.id.operation_mul_btn, "16.0", "16.0", "256.0");
93+
}
94+
95+
private void performOperation(int btnOperationResId, String operandOne,
96+
String operandTwo, String expectedResult) {
97+
// Type the two operands in the EditText fields
98+
onView(withId(R.id.operand_one_edit_text)).perform(typeText(operandOne),
99+
closeSoftKeyboard());
100+
onView(withId(R.id.operand_two_edit_text)).perform(typeText(operandTwo),
101+
closeSoftKeyboard());
102+
103+
// Click on a given operation button
104+
onView(withId(btnOperationResId)).perform(click());
105+
106+
// Check the expected test is displayed in the Ui
107+
onView(withId(R.id.operation_result_text_view)).check(matches(withText(expectedResult)));
108+
}
109+
110+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
Copyright 2020 The Android Open Source Project
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
-->
17+
18+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
19+
package="com.example.android.testing.androidtestorchestratorsample" >
20+
21+
<application
22+
android:icon="@drawable/ic_launcher"
23+
android:label="@string/app_name"
24+
android:theme="@style/AppTheme" >
25+
<activity
26+
android:name=".CalculatorActivity"
27+
android:label="@string/app_name"
28+
android:exported="true" >
29+
<intent-filter>
30+
<action android:name="android.intent.action.MAIN" />
31+
32+
<category android:name="android.intent.category.LAUNCHER" />
33+
</intent-filter>
34+
</activity>
35+
</application>
36+
37+
</manifest>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright 2020, The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.android.testing.androidtestorchestratorsample;
18+
19+
import static com.google.common.base.Preconditions.checkArgument;
20+
21+
/**
22+
* A simple calculator with a basic set of operations.
23+
*/
24+
public class Calculator {
25+
26+
public enum Operator {ADD, SUB, DIV, MUL}
27+
28+
/**
29+
* Addition operation
30+
*/
31+
public double add(double firstOperand, double secondOperand) {
32+
return firstOperand + secondOperand;
33+
}
34+
35+
/**
36+
* Substract operation
37+
*/
38+
public double sub(double firstOperand, double secondOperand) {
39+
return firstOperand - secondOperand;
40+
}
41+
42+
/**
43+
* Divide operation
44+
*/
45+
public double div(double firstOperand, double secondOperand) {
46+
checkArgument(secondOperand != 0, "secondOperand must be != 0, you cannot divide by zero");
47+
return firstOperand / secondOperand;
48+
}
49+
50+
/**
51+
* Multiply operation
52+
*/
53+
public double mul(double firstOperand, double secondOperand) {
54+
55+
return firstOperand * secondOperand;
56+
}
57+
}

0 commit comments

Comments
 (0)