├── .gitignore ├── AndroidTestingBox ├── .gitignore ├── app │ ├── .gitignore │ ├── build.gradle │ ├── jgiven-reports │ │ └── com.guddy.android_testing_box.JGivenSumTest.json │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ ├── assets │ │ │ └── features │ │ │ │ └── main.feature │ │ ├── java │ │ │ └── com │ │ │ │ └── guddy │ │ │ │ └── android_testing_box │ │ │ │ └── ui │ │ │ │ ├── CucumberInstrumentationRunner.java │ │ │ │ ├── CucumberMainActivitySteps.java │ │ │ │ ├── EspressoJGivenMainActivityTest.java │ │ │ │ ├── HCRMainActivityTest.java │ │ │ │ ├── MainActivityTest.java │ │ │ │ └── ScreenshotUtils.java │ │ └── kotlin │ │ │ └── com │ │ │ └── guddy │ │ │ └── android_testing_box │ │ │ └── KMainActivityTest.kt │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── guddy │ │ │ │ └── android_testing_box │ │ │ │ ├── MainActivity.kt │ │ │ │ ├── Sum.java │ │ │ │ └── zester │ │ │ │ ├── NameParser.java │ │ │ │ └── Person.java │ │ └── res │ │ │ ├── layout │ │ │ └── activity_main.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── values-w820dp │ │ │ └── dimens.xml │ │ │ └── values │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ ├── sharedTest │ │ └── java │ │ │ └── com │ │ │ └── guddy │ │ │ └── android_testing_box │ │ │ └── bdd │ │ │ └── BddCanvas.java │ │ └── test │ │ ├── java │ │ └── com │ │ │ └── guddy │ │ │ └── android_testing_box │ │ │ ├── FrutillaSumTest.java │ │ │ ├── HCRSumTest.java │ │ │ ├── JGivenSumTest.java │ │ │ ├── RobolectricMainActivityTest.java │ │ │ ├── SpectrumSumTest.java │ │ │ ├── cucumber │ │ │ ├── SumSteps.java │ │ │ └── SumTestRunner.java │ │ │ └── zester │ │ │ └── ZesterExampleTest.java │ │ ├── kotlin │ │ └── com │ │ │ └── guddy │ │ │ └── android_testing_box │ │ │ ├── KHCRSumTest.kt │ │ │ └── SpekSumTest.kt │ │ └── resources │ │ └── features │ │ └── sum │ │ └── sum.feature ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle ├── LICENSE ├── README.md ├── _config.yml └── assets ├── README.md └── logo.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the ART/Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | 16 | # Gradle files 17 | .gradle/ 18 | build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Log Files 27 | *.log 28 | 29 | # Android Studio Navigation editor temp files 30 | .navigation/ 31 | 32 | # Android Studio captures folder 33 | captures/ 34 | 35 | # Intellij 36 | *.iml 37 | .idea/workspace.xml 38 | 39 | # Keystore files 40 | *.jks 41 | 42 | .DS_Store 43 | -------------------------------------------------------------------------------- /AndroidTestingBox/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /AndroidTestingBox/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /AndroidTestingBox/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'me.tatarka.retrolambda' 4 | 5 | buildscript { 6 | repositories { 7 | mavenCentral() 8 | jcenter() 9 | } 10 | dependencies { 11 | classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.0-M2' 12 | classpath 'me.tatarka:gradle-retrolambda:3.3.1' 13 | } 14 | } 15 | 16 | android { 17 | compileSdkVersion 25 18 | buildToolsVersion "25.0.2" 19 | 20 | defaultConfig { 21 | applicationId "com.guddy.android_testing_box" 22 | minSdkVersion 23 23 | targetSdkVersion 25 24 | versionCode 1 25 | versionName "1.0" 26 | //testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 27 | testApplicationId "com.guddy.android_testing_box.ui" 28 | testInstrumentationRunner "com.guddy.android_testing_box.ui.CucumberInstrumentationRunner" 29 | multiDexEnabled true 30 | } 31 | 32 | buildTypes { 33 | release { 34 | minifyEnabled false 35 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 36 | } 37 | } 38 | 39 | sourceSets { 40 | String sharedTestDir = 'src/sharedTest/java' 41 | test { 42 | java.srcDir sharedTestDir 43 | } 44 | androidTest { 45 | java.srcDir sharedTestDir 46 | assets.srcDirs = ['src/androidTest/assets'] 47 | } 48 | 49 | main.java.srcDirs += 'src/main/kotlin' 50 | test.java.srcDirs += 'src/test/kotlin' 51 | androidTest.java.srcDirs += 'src/androidTest/kotlin' 52 | } 53 | 54 | compileOptions { 55 | targetCompatibility 1.8 56 | sourceCompatibility 1.8 57 | } 58 | 59 | configurations.all { 60 | resolutionStrategy.force 'com.android.support:support-media-compat:25.1.1' 61 | resolutionStrategy.force 'com.android.support:support-core-ui:25.1.1' 62 | resolutionStrategy.force 'com.android.support:support-core-utils:25.1.1' 63 | resolutionStrategy.force 'com.android.support:support-vector-drawable:25.1.1' 64 | resolutionStrategy.force 'com.android.support:appcompat-v7:25.1.1' 65 | resolutionStrategy.force 'com.android.support:support-fragment:25.1.1' 66 | resolutionStrategy.force 'com.android.support:support-compat:25.1.1' 67 | resolutionStrategy.force 'com.android.support:animated-vector-drawable:25.1.1' 68 | resolutionStrategy.force 'com.android.support:support-v4:25.1.1' 69 | resolutionStrategy.force 'com.android.support:support-annotations:25.1.1' 70 | } 71 | } 72 | 73 | configurations { 74 | jgivenReport 75 | } 76 | 77 | dependencies { 78 | compile fileTree(dir: 'libs', include: ['*.jar']) 79 | 80 | compile 'com.android.support:multidex:1.0.1' 81 | 82 | compile 'com.android.support:appcompat-v7:25.1.1' 83 | compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" 84 | compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.5' 85 | 86 | testCompile 'junit:junit:4.12' 87 | testCompile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" 88 | testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version" 89 | testCompile 'org.jetbrains.spek:spek-api:1.0.89' 90 | testCompile 'org.jetbrains.spek:spek-junit-platform-engine:1.0.89' 91 | testCompile 'org.junit.platform:junit-platform-runner:1.0.0-M3' 92 | testCompile 'org.amshove.kluent:kluent:1.8' 93 | testCompile 'com.google.truth:truth:0.32' 94 | testCompile 'com.greghaskins:spectrum:0.7.1' 95 | testCompile 'com.github.ignaciotcrespo:frutilla:0.7.1' 96 | testCompile 'de.bechte.junit:junit-hierarchicalcontextrunner:4.12.1' 97 | testCompile 'com.tngtech.jgiven:jgiven-junit:0.14.1' 98 | testCompile 'com.tngtech.jgiven:jgiven-html5-report:0.14.1' 99 | testCompile 'org.robolectric:robolectric:3.2.2' 100 | testCompile 'org.robolectric:shadows-multidex:3.2.2' 101 | testCompile 'org.robolectric:shadows-support-v4:3.2.2' 102 | testCompile 'org.khronos:opengl-api:gl1.1-android-2.1_r1' 103 | testCompile 'info.cukes:cucumber-java:1.2.5' 104 | testCompile 'info.cukes:cucumber-junit:1.2.5' 105 | 106 | androidTestCompile 'com.tngtech.jgiven:jgiven-android:0.14.1' 107 | 108 | jgivenReport 'com.tngtech.jgiven:jgiven-html5-report:0.14.1' 109 | jgivenReport 'org.slf4j:slf4j-simple:1.7.24' 110 | 111 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 112 | exclude group: 'com.android.support', module: 'support-annotations' 113 | }) 114 | androidTestCompile('org.jetbrains.spek:spek-api:1.0.89') { 115 | exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib' 116 | exclude group: 'org.jetbrains.kotlin', module: 'kotlin-runtime' 117 | } 118 | androidTestCompile('org.jetbrains.spek:spek-junit-platform-engine:1.0.89') { 119 | exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib' 120 | exclude group: 'org.jetbrains.kotlin', module: 'kotlin-runtime' 121 | } 122 | androidTestCompile('com.android.support.test:runner:0.5') { 123 | exclude group: 'com.android.support', module: 'support-annotations' 124 | } 125 | androidTestCompile 'com.jayway.android.robotium:robotium-solo:5.6.3' 126 | androidTestCompile('com.android.support.test:rules:0.5') { 127 | exclude group: 'com.android.support', module: 'support-annotations' 128 | } 129 | androidTestCompile 'com.google.truth:truth:0.32' 130 | androidTestCompile 'de.bechte.junit:junit-hierarchicalcontextrunner:4.12.1' 131 | androidTestCompile 'info.cukes:cucumber-android:1.2.0@jar' 132 | androidTestCompile 'info.cukes:cucumber-picocontainer:1.2.0' 133 | } 134 | 135 | // jgiven for unit testing 136 | 137 | task jgivenReport(type: JavaExec, dependsOn: 'test') { 138 | main = 'com.tngtech.jgiven.report.ReportGenerator' 139 | args '--sourceDir=jgiven-reports', 140 | '--targetDir=jgiven-reports/html', 141 | '--format=html' 142 | classpath = configurations.testCompile 143 | } 144 | 145 | // jgiven for UI testing 146 | 147 | def targetDir = 'build/reports/jgiven/json' 148 | def adb = android.getAdbExe().toString() 149 | def reportsDir = '/storage/emulated/0/Download/jgiven-reports' 150 | 151 | task cleanJGivenReports(type: Delete) { 152 | delete targetDir 153 | } 154 | 155 | task pullJGivenReports(type: Exec, dependsOn: cleanJGivenReports) { 156 | doFirst { 157 | if (!file(targetDir).mkdirs()) { 158 | println("Cannot create dir "+targetDir) 159 | } 160 | } 161 | 162 | commandLine adb, 'pull', reportsDir, targetDir 163 | 164 | doLast { 165 | println("Pulled "+reportsDir+" to "+targetDir); 166 | } 167 | } 168 | 169 | task cleanJGivenReportsFromDevice(type: Exec) { 170 | commandLine adb, 'shell', 'rm -rf', reportsDir 171 | 172 | doLast { 173 | println("Deleted "+reportsDir) 174 | } 175 | } 176 | 177 | pullJGivenReports.finalizedBy(cleanJGivenReportsFromDevice) 178 | 179 | task cleanJGivenHtmlReport(type: Delete) { 180 | delete 'build/reports/jgiven/html' 181 | } 182 | 183 | task jgivenHtml5Report(type: JavaExec, dependsOn: cleanJGivenHtmlReport) { 184 | main = 'com.tngtech.jgiven.report.ReportGenerator' 185 | args '--sourceDir=build/reports/jgiven/json', 186 | '--targetDir=build/reports/jgiven/html', 187 | '--format=html5', 188 | '--exclude-empty-scenarios=true' 189 | classpath = configurations.jgivenReport 190 | } 191 | 192 | pullJGivenReports.finalizedBy(jgivenHtml5Report) 193 | 194 | tasks.whenTaskAdded { task -> 195 | if (task.name == 'connectedAndroidTest') { 196 | task.finalizedBy 'pullJGivenReports' 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /AndroidTestingBox/app/jgiven-reports/com.guddy.android_testing_box.JGivenSumTest.json: -------------------------------------------------------------------------------- 1 | { 2 | "className": "com.guddy.android_testing_box.JGivenSumTest", 3 | "name": "J Given Sum", 4 | "scenarios": [ 5 | { 6 | "className": "com.guddy.android_testing_box.JGivenSumTest", 7 | "testMethodName": "addition_isCorrect", 8 | "description": "addition isCorrect", 9 | "tagIds": [], 10 | "explicitParameters": [], 11 | "derivedParameters": [], 12 | "casesAsTable": false, 13 | "scenarioCases": [ 14 | { 15 | "caseNr": 1, 16 | "steps": [ 17 | { 18 | "name": "first number $", 19 | "words": [ 20 | { 21 | "value": "Given", 22 | "isIntroWord": true 23 | }, 24 | { 25 | "value": "first number" 26 | }, 27 | { 28 | "value": "1", 29 | "argumentInfo": { 30 | "argumentName": "piA", 31 | "formattedValue": "1" 32 | } 33 | } 34 | ], 35 | "status": "PASSED", 36 | "durationInNanos": 303573199 37 | }, 38 | { 39 | "name": "second number $", 40 | "words": [ 41 | { 42 | "value": "and", 43 | "isIntroWord": true 44 | }, 45 | { 46 | "value": "second number" 47 | }, 48 | { 49 | "value": "3", 50 | "argumentInfo": { 51 | "argumentName": "piB", 52 | "formattedValue": "3" 53 | } 54 | } 55 | ], 56 | "status": "PASSED", 57 | "durationInNanos": 257145 58 | }, 59 | { 60 | "name": "computing sum", 61 | "words": [ 62 | { 63 | "value": "When", 64 | "isIntroWord": true 65 | }, 66 | { 67 | "value": "computing sum" 68 | } 69 | ], 70 | "status": "PASSED", 71 | "durationInNanos": 34212 72 | }, 73 | { 74 | "name": "it should be $", 75 | "words": [ 76 | { 77 | "value": "Then", 78 | "isIntroWord": true 79 | }, 80 | { 81 | "value": "it should be" 82 | }, 83 | { 84 | "value": "4", 85 | "argumentInfo": { 86 | "argumentName": "piExpected", 87 | "formattedValue": "4" 88 | } 89 | } 90 | ], 91 | "status": "PASSED", 92 | "durationInNanos": 243399 93 | } 94 | ], 95 | "explicitArguments": [], 96 | "derivedArguments": [], 97 | "status": "SUCCESS", 98 | "success": true, 99 | "durationInNanos": 465625361 100 | } 101 | ], 102 | "durationInNanos": 465625361, 103 | "executionStatus": "SUCCESS" 104 | } 105 | ], 106 | "tagMap": {} 107 | } -------------------------------------------------------------------------------- /AndroidTestingBox/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/Romain/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /AndroidTestingBox/app/src/androidTest/assets/features/main.feature: -------------------------------------------------------------------------------- 1 | Feature: Main activity 2 | 3 | Scenario: Click on the button 4 | Given the initial state is shown 5 | When clicking on the button 6 | Then the text changed to "Text changed after button click" -------------------------------------------------------------------------------- /AndroidTestingBox/app/src/androidTest/java/com/guddy/android_testing_box/ui/CucumberInstrumentationRunner.java: -------------------------------------------------------------------------------- 1 | package com.guddy.android_testing_box.ui; 2 | 3 | import android.os.Bundle; 4 | import android.support.test.runner.MonitoringInstrumentation; 5 | 6 | import cucumber.api.android.CucumberInstrumentationCore; 7 | 8 | public class CucumberInstrumentationRunner extends MonitoringInstrumentation { 9 | 10 | private final CucumberInstrumentationCore mInstrumentationCore = new CucumberInstrumentationCore(this); 11 | 12 | @Override 13 | public void onCreate(Bundle arguments) { 14 | super.onCreate(arguments); 15 | 16 | mInstrumentationCore.create(arguments); 17 | start(); 18 | } 19 | 20 | @Override 21 | public void onStart() { 22 | super.onStart(); 23 | 24 | waitForIdleSync(); 25 | mInstrumentationCore.start(); 26 | } 27 | } -------------------------------------------------------------------------------- /AndroidTestingBox/app/src/androidTest/java/com/guddy/android_testing_box/ui/CucumberMainActivitySteps.java: -------------------------------------------------------------------------------- 1 | package com.guddy.android_testing_box.ui; 2 | 3 | import android.test.ActivityInstrumentationTestCase2; 4 | 5 | import com.guddy.android_testing_box.MainActivity; 6 | import com.guddy.android_testing_box.R; 7 | 8 | import cucumber.api.CucumberOptions; 9 | import cucumber.api.java.en.Given; 10 | import cucumber.api.java.en.Then; 11 | import cucumber.api.java.en.When; 12 | 13 | import static android.support.test.espresso.Espresso.onView; 14 | import static android.support.test.espresso.action.ViewActions.click; 15 | import static android.support.test.espresso.assertion.ViewAssertions.matches; 16 | import static android.support.test.espresso.matcher.ViewMatchers.withId; 17 | import static android.support.test.espresso.matcher.ViewMatchers.withText; 18 | 19 | @CucumberOptions(features = "features") 20 | public class CucumberMainActivitySteps extends ActivityInstrumentationTestCase2 { 21 | 22 | public CucumberMainActivitySteps() { 23 | super(MainActivity.class); 24 | } 25 | 26 | @Given("^the initial state is shown$") 27 | public void the_initial_main_activity_is_shown() { 28 | // Call the activity before each test. 29 | getActivity(); 30 | } 31 | 32 | @When("^clicking on the button$") 33 | public void clicking_the_Click_Me_button() { 34 | onView(withId(R.id.ActivityMain_Button)).perform(click()); 35 | } 36 | 37 | @Then("^the text changed to \"([^\"]*)\"$") 38 | public void text_$_is_shown(final String s) { 39 | onView(withId(R.id.ActivityMain_TextView)).check(matches(withText(s))); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /AndroidTestingBox/app/src/androidTest/java/com/guddy/android_testing_box/ui/EspressoJGivenMainActivityTest.java: -------------------------------------------------------------------------------- 1 | package com.guddy.android_testing_box.ui; 2 | 3 | import android.support.test.rule.ActivityTestRule; 4 | import android.support.test.runner.AndroidJUnit4; 5 | 6 | import com.guddy.android_testing_box.MainActivity; 7 | import com.guddy.android_testing_box.R; 8 | import com.tngtech.jgiven.CurrentStep; 9 | import com.tngtech.jgiven.Stage; 10 | import com.tngtech.jgiven.annotation.Quoted; 11 | import com.tngtech.jgiven.annotation.ScenarioState; 12 | import com.tngtech.jgiven.attachment.Attachment; 13 | import com.tngtech.jgiven.attachment.MediaType; 14 | import com.tngtech.jgiven.integration.android.AndroidJGivenTestRule; 15 | import com.tngtech.jgiven.junit.SimpleScenarioTest; 16 | 17 | import org.junit.Rule; 18 | import org.junit.Test; 19 | import org.junit.runner.RunWith; 20 | 21 | import static android.support.test.espresso.Espresso.onView; 22 | import static android.support.test.espresso.action.ViewActions.click; 23 | import static android.support.test.espresso.assertion.ViewAssertions.matches; 24 | import static android.support.test.espresso.matcher.ViewMatchers.withId; 25 | import static android.support.test.espresso.matcher.ViewMatchers.withText; 26 | 27 | @RunWith(AndroidJUnit4.class) 28 | public class EspressoJGivenMainActivityTest extends 29 | SimpleScenarioTest { 30 | 31 | @Rule 32 | @ScenarioState 33 | public ActivityTestRule activityTestRule = new ActivityTestRule<>(MainActivity.class); 34 | 35 | @Rule 36 | public AndroidJGivenTestRule androidJGivenTestRule = new AndroidJGivenTestRule(getScenario()); 37 | 38 | @Test 39 | public void clicking_ClickMe_changes_the_text() { 40 | given().the_initial_main_activity_is_shown() 41 | .with().text("AndroidTestingBox"); 42 | when().clicking_the_Click_Me_button(); 43 | then().text_$_is_shown("Text changed after button click"); 44 | } 45 | 46 | public static class Steps extends Stage { 47 | @ScenarioState 48 | CurrentStep currentStep; 49 | 50 | @ScenarioState 51 | ActivityTestRule activityTestRule; 52 | 53 | public Steps the_initial_main_activity_is_shown() { 54 | // nothing to do, just for reporting 55 | return this; 56 | } 57 | 58 | public Steps clicking_the_Click_Me_button() { 59 | onView(withId(R.id.ActivityMain_Button)).perform(click()); 60 | return this; 61 | } 62 | 63 | public Steps text(@Quoted String s) { 64 | return text_$_is_shown(s); 65 | } 66 | 67 | public Steps text_$_is_shown(@Quoted String s) { 68 | onView(withId(R.id.ActivityMain_TextView)).check(matches(withText(s))); 69 | takeScreenshot(); 70 | return this; 71 | } 72 | 73 | private void takeScreenshot() { 74 | currentStep.addAttachment( 75 | Attachment.fromBinaryBytes(ScreenshotUtils.takeScreenshot(activityTestRule.getActivity()), MediaType.PNG) 76 | .showDirectly()); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /AndroidTestingBox/app/src/androidTest/java/com/guddy/android_testing_box/ui/HCRMainActivityTest.java: -------------------------------------------------------------------------------- 1 | package com.guddy.android_testing_box.ui; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.rule.ActivityTestRule; 6 | 7 | import com.guddy.android_testing_box.MainActivity; 8 | import com.guddy.android_testing_box.R; 9 | import com.robotium.solo.Solo; 10 | 11 | import org.junit.After; 12 | import org.junit.Before; 13 | import org.junit.Rule; 14 | import org.junit.Test; 15 | import org.junit.runner.RunWith; 16 | 17 | import de.bechte.junit.runners.context.HierarchicalContextRunner; 18 | 19 | import static com.google.common.truth.Truth.assertThat; 20 | 21 | @RunWith(HierarchicalContextRunner.class) 22 | public class HCRMainActivityTest { 23 | 24 | public class GivenMainActivity { 25 | @Rule 26 | public final ActivityTestRule mActivityTestRule = new ActivityTestRule<>(MainActivity.class, true, false); 27 | 28 | //region Fields 29 | private Solo mSolo; 30 | private MainActivity mActivity; 31 | private Context mContextTarget; 32 | //endregion 33 | 34 | @Before 35 | public void setUp() throws Exception { 36 | mActivity = mActivityTestRule.getActivity(); 37 | mSolo = new Solo(InstrumentationRegistry.getInstrumentation(), mActivity); 38 | mContextTarget = InstrumentationRegistry.getTargetContext(); 39 | } 40 | 41 | @After 42 | public void tearDown() throws Exception { 43 | mSolo.finishOpenedActivities(); 44 | } 45 | 46 | public class WhenLaunchingActivity { 47 | @Before 48 | public void setUp() { 49 | mActivity = mActivityTestRule.launchActivity(null); 50 | } 51 | 52 | @Test 53 | public void thenItShouldDisplayAppName() { 54 | final boolean lbFoundTheRepo = mSolo.waitForText(mContextTarget.getString(R.string.app_name), 1, 5000L, true); 55 | assertThat(lbFoundTheRepo); 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /AndroidTestingBox/app/src/androidTest/java/com/guddy/android_testing_box/ui/MainActivityTest.java: -------------------------------------------------------------------------------- 1 | package com.guddy.android_testing_box.ui; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.rule.ActivityTestRule; 6 | import android.support.test.runner.AndroidJUnit4; 7 | 8 | import com.guddy.android_testing_box.MainActivity; 9 | import com.guddy.android_testing_box.R; 10 | import com.robotium.solo.Solo; 11 | 12 | import org.junit.After; 13 | import org.junit.Before; 14 | import org.junit.Rule; 15 | import org.junit.Test; 16 | import org.junit.runner.RunWith; 17 | 18 | import static com.google.common.truth.Truth.assertThat; 19 | import static com.guddy.android_testing_box.bdd.BddCanvas.given; 20 | import static com.guddy.android_testing_box.bdd.BddCanvas.then; 21 | import static com.guddy.android_testing_box.bdd.BddCanvas.when; 22 | 23 | @RunWith(AndroidJUnit4.class) 24 | public class MainActivityTest { 25 | //region Rule 26 | @Rule 27 | public final ActivityTestRule mActivityTestRule = new ActivityTestRule<>(MainActivity.class, true, false); 28 | //endregion 29 | 30 | //region Fields 31 | private Solo mSolo; 32 | private MainActivity mActivity; 33 | private Context mContextTarget; 34 | //endregion 35 | 36 | //region Test lifecycle 37 | @Before 38 | public void setUp() throws Exception { 39 | mActivity = mActivityTestRule.getActivity(); 40 | mSolo = new Solo(InstrumentationRegistry.getInstrumentation(), mActivity); 41 | mContextTarget = InstrumentationRegistry.getTargetContext(); 42 | } 43 | 44 | @After 45 | public void tearDown() throws Exception { 46 | mSolo.finishOpenedActivities(); 47 | } 48 | //endregion 49 | 50 | //region Test methods 51 | @Test 52 | public void testTextDisplayed() throws Exception { 53 | given("the main activity", () -> { 54 | 55 | when("launching activity", () -> { 56 | mActivity = mActivityTestRule.launchActivity(null); 57 | 58 | then("should display 'app_name'", () -> { 59 | final boolean lbFoundAppName = mSolo.waitForText(mContextTarget.getString(R.string.app_name), 1, 5000L, true); 60 | assertThat(lbFoundAppName); 61 | }); 62 | }); 63 | }); 64 | } 65 | //endregion 66 | } 67 | -------------------------------------------------------------------------------- /AndroidTestingBox/app/src/androidTest/java/com/guddy/android_testing_box/ui/ScreenshotUtils.java: -------------------------------------------------------------------------------- 1 | package com.guddy.android_testing_box.ui; 2 | 3 | import android.app.Activity; 4 | import android.graphics.Bitmap; 5 | import android.support.annotation.NonNull; 6 | import android.view.View; 7 | 8 | import java.io.ByteArrayOutputStream; 9 | 10 | public final class ScreenshotUtils { 11 | 12 | private ScreenshotUtils() {} 13 | 14 | public static byte[] takeScreenshot(@NonNull final Activity poActivity) { 15 | final View loView = poActivity.getWindow().getDecorView().getRootView(); 16 | loView.setDrawingCacheEnabled(true); 17 | final Bitmap loBitmap = Bitmap.createBitmap(loView.getDrawingCache()); 18 | loView.setDrawingCacheEnabled(false); 19 | final ByteArrayOutputStream loBaos = new ByteArrayOutputStream(); 20 | loBitmap.compress(Bitmap.CompressFormat.PNG, 100, loBaos); 21 | return loBaos.toByteArray(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /AndroidTestingBox/app/src/androidTest/kotlin/com/guddy/android_testing_box/KMainActivityTest.kt: -------------------------------------------------------------------------------- 1 | package com.guddy.android_testing_box 2 | 3 | import android.content.Context 4 | import android.support.test.InstrumentationRegistry 5 | import android.support.test.rule.ActivityTestRule 6 | import android.support.test.runner.AndroidJUnit4 7 | import com.robotium.solo.Solo 8 | import org.junit.After 9 | import org.junit.Assert.assertTrue 10 | import org.junit.Before 11 | import org.junit.Rule 12 | import org.junit.Test 13 | import org.junit.runner.RunWith 14 | 15 | @RunWith(AndroidJUnit4::class) 16 | class KMainActivityTest() { 17 | //region Rule 18 | @get:Rule 19 | val mActivityTestRule = ActivityTestRule(MainActivity::class.java, true, false) 20 | //endregion 21 | 22 | private var mActivity: MainActivity? = null 23 | private var mSolo: Solo? = null 24 | private var mContextTarget: Context? = null 25 | //endregion 26 | 27 | //region Test lifecycle 28 | @Before 29 | @Throws(Exception::class) 30 | fun setUp() { 31 | mActivity = mActivityTestRule.activity 32 | mSolo = Solo(InstrumentationRegistry.getInstrumentation(), mActivity) 33 | mContextTarget = InstrumentationRegistry.getTargetContext() 34 | } 35 | 36 | @After 37 | @Throws(Exception::class) 38 | fun tearDown() { 39 | mSolo!!.finishOpenedActivities() 40 | } 41 | //endregion 42 | 43 | //region Test methods 44 | @Test 45 | fun testTextDisplayed() { 46 | mActivity = mActivityTestRule.launchActivity(null) 47 | 48 | val lbFoundTheRepo = mSolo!!.waitForText(mContextTarget!!.getString(R.string.app_name), 1, 5000L, true) 49 | assertTrue(lbFoundTheRepo) 50 | } 51 | //endregion 52 | } 53 | -------------------------------------------------------------------------------- /AndroidTestingBox/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /AndroidTestingBox/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /AndroidTestingBox/app/src/main/java/com/guddy/android_testing_box/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.guddy.android_testing_box 2 | 3 | import android.os.Bundle 4 | import android.support.v7.app.AppCompatActivity 5 | import android.view.View 6 | import android.widget.TextView 7 | 8 | class MainActivity : AppCompatActivity() { 9 | 10 | override fun onCreate(savedInstanceState: Bundle?) { 11 | super.onCreate(savedInstanceState) 12 | setContentView(R.layout.activity_main) 13 | 14 | val textView: TextView = findViewById(R.id.ActivityMain_TextView) as TextView 15 | val button = findViewById(R.id.ActivityMain_Button) 16 | button.setOnClickListener({ view: View -> textView.setText(R.string.text_changed_after_button_click) }) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /AndroidTestingBox/app/src/main/java/com/guddy/android_testing_box/Sum.java: -------------------------------------------------------------------------------- 1 | package com.guddy.android_testing_box; 2 | 3 | import org.apache.commons.lang3.concurrent.ConcurrentException; 4 | import org.apache.commons.lang3.concurrent.LazyInitializer; 5 | 6 | public class Sum { 7 | public final int a; 8 | public final int b; 9 | private final LazyInitializer mSum; 10 | 11 | public Sum(int a, int b) { 12 | this.a = a; 13 | this.b = b; 14 | mSum = new LazyInitializer() { 15 | @Override 16 | protected Integer initialize() throws ConcurrentException { 17 | return Sum.this.a + Sum.this.b; 18 | } 19 | }; 20 | } 21 | 22 | public int getSum() throws ConcurrentException { 23 | return mSum.get(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /AndroidTestingBox/app/src/main/java/com/guddy/android_testing_box/zester/NameParser.java: -------------------------------------------------------------------------------- 1 | package com.guddy.android_testing_box.zester; 2 | 3 | public class NameParser { 4 | public Person findPersonWithLastName(final String[] names, final String lastNameToFind) { 5 | Person result = null; 6 | for (int i = 0; i <= names.length; i++) { // bug 1 7 | final String[] parts = names[i].split(" "); 8 | final String firstName = parts[0]; 9 | final String lastName = parts[1]; 10 | if (lastName.equals(lastNameToFind)) { 11 | result = new Person(firstName, lastName); 12 | break; 13 | } 14 | } 15 | return result; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /AndroidTestingBox/app/src/main/java/com/guddy/android_testing_box/zester/Person.java: -------------------------------------------------------------------------------- 1 | package com.guddy.android_testing_box.zester; 2 | 3 | public class Person { 4 | private final String firstName; 5 | private final String lastName; 6 | 7 | public Person(final String firstName, final String lastName) { 8 | this.firstName = firstName; 9 | this.lastName = lastName; 10 | } 11 | 12 | public String getFirstName() { 13 | return firstName; 14 | } 15 | 16 | public String getLastName() { 17 | return firstName; // bug 2 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /AndroidTestingBox/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 |