AndroidTestingBox
Android project to experiment various testing tools
Install / Use
/learn @RoRoche/AndroidTestingBoxREADME
AndroidTestingBox
Android project to experiment various testing tools. It targets Java and Kotlin languages. Priority is given to fluency and ease of use. The idea is to provide a toolbox to write elegant and intelligible tests, with modern techniques like behavior-driven testing frameworks or fluent assertions.

- AndroidTestingBox in the news
- System under test (SUT)
- JUnit
- Kotlin
- Android
- IDE configuration
- Nota Bene
- Bibliography
- Interesting repositories
- Interesting articles
- Resources
- Logo credits
AndroidTestingBox in the news
System under test (SUT)
Simple Java class
public class Sum {
public final int a;
public final int b;
private final LazyInitializer<Integer> mSum;
public Sum(int a, int b) {
this.a = a;
this.b = b;
mSum = new LazyInitializer<Integer>() {
@Override
protected Integer initialize() throws ConcurrentException {
return Sum.this.a + Sum.this.b;
}
};
}
public int getSum() throws ConcurrentException {
return mSum.get();
}
}
Android Activity
Here stands the layout file:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:id="@+id/activity_main"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/ActivityMain_TextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="@string/app_name"/>
<Button
android:id="@+id/ActivityMain_Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/ActivityMain_TextView"
android:layout_centerHorizontal="true"
android:text="@string/click_me"/>
</RelativeLayout>
and here stands the corresponding Activity:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val textView: TextView = findViewById(R.id.ActivityMain_TextView) as TextView
val button = findViewById(R.id.ActivityMain_Button)
button.setOnClickListener({ view: View -> textView.setText(R.string.text_changed_after_button_click) })
}
}
JUnit
Fluent assertions: truth
Alternative: AssertJ
Frutilla
@RunWith(value = org.frutilla.FrutillaTestRunner.class)
public class FrutillaSumTest {
@Frutilla(
Given = "two numbers a = 1 and b = 3",
When = "computing the sum of these 2 numbers",
Then = "should compute sum = 4"
)
@Test
public void test_addition_isCorrect() throws Exception {
given("two numbers", () -> {
final int a = 1;
final int b = 3;
when("computing the sum of these 2 numbers", () -> {
final Sum sum = new Sum(a, b);
then("should compute sum = 4", () -> assertThat(sum.getSum()).isEqualTo(4));
});
});
}
}
Fluent test method names
Specifications framework: Spectrum
- https://github.com/greghaskins/spectrum
- http://www.greghaskins.com/archive/introducing-spectrum-bdd-style-test-runner-for-java-junit
import static com.google.common.truth.Truth.assertThat;
import static com.greghaskins.spectrum.Spectrum.describe;
import static com.greghaskins.spectrum.Spectrum.it;
@RunWith(Spectrum.class)
public class SpectrumSumTest {
{
describe("Given two numbers a = 1 and b = 3", () -> {
final int a = 1;
final int b = 3;
it("computing the sum of these 2 numbers, should compute sum = 4", () -> {
final Sum sum = new Sum(a, b);
assertThat(sum.getSum()).isEqualTo(4);
});
});
}
}
Alternative: Oleaster
Hierarchies in JUnit: junit-hierarchicalcontextrunner
@RunWith(HierarchicalContextRunner.class)
public class HCRSumTest {
public class GivenTwoNumbers1And3 {
private int a = 1;
private int b = 3;
@Before
public void setUp() {
a = 1;
b = 3;
}
public class WhenComputingSum {
private Sum sum;
@Before
public void setUp() {
sum = new Sum(a, b);
}
@Test
public void thenShouldBeEqualTo4() throws ConcurrentException {
assertThat(sum.getSum()).isEqualTo(4);
}
}
public class WhenMultiplying {
private int multiply;
@Before
public void setUp() {
multiply = a * b;
}
@Test
public void thenShouldBeEqualTo3() throws ConcurrentException {
assertThat(multiply).isEqualTo(3);
}
}
}
}
Novelty to consider: JUnit 5 Nested Tests
- http://junit.org/junit5/docs/current/user-guide/#writing-tests-nested
- The
@Nestedand@DisplayNameannotations allow developers to reach an elegant "given/when/then" canvas
BDD tools
Cucumber
- Define the
.featurefile:
Feature: Sum computation
Scenario Outline: Sum 2 integers
Given two int <a> and <b> to sum
When computing sum
Then it should be <sum>
Examples:
| a | b | sum |
| 1 | 3 | 4 |
| -1 | -3 | -4 |
| -1 | 3 | 2 |
- Define the corresponding steps:
public class SumSteps {
Sum moSum;
int miSum;
@Given("^two int (-?\\d+) and (-?\\d+) to sum$")
public void twoIntToSum(final int a, final int b) {
moSum = new Sum(a, b);
}
@When("^computing sum$")
public void computingSum() throws ConcurrentException {
miSum = moSum.getSum();
}
@Then("^it should be (-?\\d+)$")
public void itShouldBe(final int expected) {
Assert.assertEquals(expected, miSum);
}
}
- Define the specific runner:
@RunWith(Cucumber.class)
@CucumberOptions(
features = "src/test/resources/"
)
public class SumTestRunner {
}
- Relevant tools:
- to write Gherkin features: Tidy Gherkin
- to display Gherkin features in Chrome a way pretty way: Pretty Gherkin
- to generating specifications from Gherkin source files: featurebook
JGiven
public class JGivenSumTest extends SimpleScenarioTest<JGivenSumTest.TestSteps> {
@Test
public void addition_isCorrect() throws ConcurrentException {
given().first_number_$(1).and().second_number_$(3);
when().computing_sum();
