Agile mobile

95
MOBILE AGILE Godfrey Nolan

Transcript of Agile mobile

Page 1: Agile mobile

MOBILE AGILEGodfrey Nolan

Page 2: Agile mobile

AGENDAAndroid (am)iOS (pm)

Page 3: Agile mobile

ANDROID AGENDAWhy??Unit, UI and API testing 101Calculator ExampleMore Tools - FIRSTETA DetroitjUnit Testing EspressoPostman / NewmanJenkins

Page 4: Agile mobile
Page 5: Agile mobile

IOS AGENDAWhy??Unit, UI and API testing 101Calculator ExampleNo really why?? (FIRST)ETA DetroitXCTest XCUI Postman / NewmanJenkins

Page 6: Agile mobile

FOLLOW ALONGgit clone http://github.com/godfreynolan/CodeCraftsman

Page 7: Agile mobile

WHYCatch more mistakesConfidently make more changesBuilt in regression testingExtend the life of your codebase

Page 8: Agile mobile
Page 9: Agile mobile

UNIT TESTING INTROpublic double add(double firstOperand, double secondOperand) { return firstOperand + secondOperand;}

@Test public void calculator_CorrectAdd_ReturnsTrue() { assertEquals(7, add(3,4); }

@Test public void calculator_CorrectAdd_ReturnsTrue() { assertEquals("Addition is broken", 7, add(3,4); }

Page 10: Agile mobile

dependencies { // Unit testing dependencies. testCompile 'junit:junit:4.12'}

Page 11: Agile mobile
Page 12: Agile mobile

UNIT TESTING 101Command lineSetup and TeardownAssertionsParametersCode Coverage

Page 13: Agile mobile

C:\Users\godfrey\AndroidStudioProjects\BasicSample>gradlew test --continueDownloading https://services.gradle.org/distributions/gradle-2.2.1-all.zip..................................................................................................................................Unzipping C:\Users\godfrey\.gradle\wrapper\dists\gradle-2.2.1-all\6dibv5rcnnqlfbq9klf8imrndn\gradleDownload https://jcenter.bintray.com/com/google/guava/guava/17.0/guava-17.0.jarDownload https://jcenter.bintray.com/com/android/tools/lint/lint-api/24.2.3/lint-api-24.2.3.jarDownload https://jcenter.bintray.com/org/ow2/asm/asm-analysis/5.0.3/asm-analysis-5.0.3.jarDownload https://jcenter.bintray.com/com/android/tools/external/lombok/lombok-ast/0.2.3/lombok-ast-0.2.3.jar:app:preBuild UP-TO-DATE:app:preDebugBuild UP-TO-DATE:app:checkDebugManifest:app:prepareDebugDependencies:app:compileDebugAidl:app:compileDebugRenderscript...:app:compileReleaseUnitTestSources:app:assembleReleaseUnitTest:app:testRelease:app:test

BUILD SUCCESSFUL

Total time: 3 mins 57.013 secs

Page 14: Agile mobile

public class CalculatorTest {

private Calculator mCalculator;

@Before public void setUp() { mCalculator = new Calculator(); }

@Test public void calculator_CorrectAdd_ReturnsTrue() { double resultAdd = mCalculator.add(3, 4); assertEquals(7, resultAdd,0); }

@After public void tearDown() { mCalculator = null; }}

Page 15: Agile mobile

UNIT TESTING 101assertEqualsassertTrueassertFalseassertNullassertNotNullassertSameassertNotSameassertThatfail

Page 16: Agile mobile

@RunWith(Parameterized.class)public class CalculatorParamTest {

private int mOperandOne, mOperandTwo, mExpectedResult; private Calculator mCalculator;

@Parameters public static Collection<Object[]> data() { return Arrays.asList(new Object[][] { {3, 4, 7}, {4, 3, 7}, {8, 2, 10}, {-1, 4, 3}, {3256, 4, 3260} }); }

public CalculatorParamTest(int mOperandOne, int mOperandTwo, int mExpectedResult) { this.mOperandOne = mOperandOne; this.mOperandTwo = mOperandTwo; this.mExpectedResult = mExpectedResult; }

@Before public void setUp() { mCalculator = new Calculator(); }

@Test public void testAdd_TwoNumbers() { int resultAdd = mCalculator.add(mOperandOne, mOperandTwo); assertEquals(mExpectedResult, resultAdd, 0); }}

Page 17: Agile mobile
Page 18: Agile mobile
Page 19: Agile mobile
Page 20: Agile mobile

ESPRESSOGUI TestingOnViewOnDatagradlew connectedCheck

Page 21: Agile mobile
Page 22: Agile mobile
Page 23: Agile mobile
Page 24: Agile mobile

@RunWith(AndroidJUnit4.class)@LargeTestpublic class MainActivityTest { @Rule public ActivityTestRule<MainActivity> activityTestRule = new ActivityTestRule<> (MainActivity.class); @Test public void helloWorldTest() { onView(withId(R.id.hello_world)) .check(matches(withText(R.string.hello_world))); }}

@Testpublic void helloWorldButtonTest(){ onView(withId(R.id.button)) .perform(click()) .check(matches(isEnabled())); }

Page 25: Agile mobile

MORE TOOLS - BUT WHY??F(ast)I(solated)R(epeatable)S(elf-verifying)T(imely) i.e. TDD not TAD

Page 26: Agile mobile
Page 27: Agile mobile

MOCKITO TEMPLATE @Test public void test() throws Exception {

// Arrange, prepare behavior Helper aMock = mock(Helper.class); when(aMock.isCalled()).thenReturn(true);

// Act testee.doSomething(aMock);

// Assert - verify interactions verify(aMock).isCalled(); }

when(methodIsCalled).thenReturn(aValue);

Page 28: Agile mobile
Page 29: Agile mobile
Page 30: Agile mobile
Page 31: Agile mobile
Page 32: Agile mobile
Page 33: Agile mobile
Page 34: Agile mobile
Page 35: Agile mobile
Page 36: Agile mobile
Page 37: Agile mobile
Page 38: Agile mobile
Page 39: Agile mobile
Page 40: Agile mobile
Page 41: Agile mobile
Page 42: Agile mobile
Page 43: Agile mobile
Page 44: Agile mobile
Page 45: Agile mobile

TROUBLE SHOOTINGrun gradlew build from the command lineAdd sdk.dir to local.propertiessdk.dir=/home/godfrey/android/sdk

Page 46: Agile mobile
Page 47: Agile mobile

TEST DRIVEN DEVELOPMENT (TDD)Unit testing vs TDDWhy TDDSample appLessons learned

Page 48: Agile mobile

TEST DRIVEN DEVELOPMENT Write test first See it fail Write simplest possible solutionto get test to pass Refactor Wash, Rinse, Repeat

Page 49: Agile mobile

TEST DRIVEN DEVELOPMENT Built in regression testingLonger life for your codebase YAGNI feature developmentRed/Green/Refactor helpskill procrastination

Page 50: Agile mobile

TDDYou can't TDD w/o unit testing

TDD means writing the testsbefore the code

TDD is more painless thanclassic unit testing

UNIT TESTINGYou can unit test w/o TDD

Unit tests don't mandate whenyou write the tests

Unit tests are often written atthe end of a coding cycle

Page 51: Agile mobile

STEPSIntroduce Continuous Integration to build codeConfigure android projects for TDDAdd minimal unit tests based on existing tests, add to CIShow team how to create unit testsAdd testing code coverage metrics to CI, expect 5-10%Add Espresso testsUnit test new features or sprouts, mock existing objectsWrap or ring fence existing code, remove unused codeRefactor wrapped code to get code coverage to 60-70%(New refactoring in Android Studio)

Page 52: Agile mobile
Page 53: Agile mobile

CONTACT [email protected]

Page 54: Agile mobile

IOS AGENDAWhy??Unit, UI and API testing 101Calculator ExampleNo really why?? (FIRST)ETA DetroitXCTest XCUI Postman / NewmanJenkins

Page 55: Agile mobile
Page 56: Agile mobile
Page 57: Agile mobile
Page 58: Agile mobile

WHYCatch more mistakesConfidently make more changesBuilt in regression testingExtend the life of your codebase

Page 59: Agile mobile
Page 60: Agile mobile

FOLLOW ALONGgit clone http://github.com/godfreynolan/CodeCraftsman

Page 61: Agile mobile
Page 62: Agile mobile
Page 63: Agile mobile
Page 64: Agile mobile
Page 65: Agile mobile
Page 66: Agile mobile
Page 67: Agile mobile
Page 68: Agile mobile
Page 69: Agile mobile
Page 70: Agile mobile
Page 71: Agile mobile
Page 72: Agile mobile
Page 73: Agile mobile
Page 74: Agile mobile

MORE TOOLS - BUT WHY??F(ast)I(solated)R(epeatable)S(elf-verifying)T(imely) i.e. TDD not TAD

Page 75: Agile mobile

TOOLS OF THE TRADEXCTest

Cuckoo (Mocking)

XCUI

Postman

Jenkins

Page 76: Agile mobile
Page 77: Agile mobile
Page 78: Agile mobile
Page 79: Agile mobile

CUCKOOAdd Cuckoo to the test target in Podfile

Pod install

Add Run Script to build phases

Add GeneratedMocks.swift file to tests

Page 80: Agile mobile
Page 81: Agile mobile

# Define output file; change "${PROJECT_NAME}Tests" to your test's root source folder, if it's not the default nameOUTPUT_FILE="./${PROJECT_NAME}Tests/GeneratedMocks.swift"echo "Generated Mocks File = ${OUTPUT_FILE}"

# Define input directory; change "${PROJECT_NAME}" to your project's root source folder, if it's not the default nameINPUT_DIR="./${PROJECT_NAME}"echo "Mocks Input Directory = ${INPUT_DIR}"

# Generate mock files; include as many input files as you'd like to create mocks for${PODS_ROOT}/Cuckoo/run generate --testable "${PROJECT_NAME}" \--output "${OUTPUT_FILE}" \"${INPUT_DIR}/JSONFetcher.swift"

# ... and so forth

# After running once, locate `GeneratedMocks.swift` and drag it into your Xcode test target group

Page 82: Agile mobile
Page 83: Agile mobile
Page 84: Agile mobile
Page 85: Agile mobile
Page 86: Agile mobile

XCUIUser Interface testing

Two options

▪Recorded tests

▪Roll your own

Page 87: Agile mobile
Page 88: Agile mobile

XCUI HAS 3 COMPONENTSXCUIApplication

Launch the app

XCUIElementQuery

Find the XCUI Element to test

XCUIElement

Perform Test

Page 89: Agile mobile
Page 90: Agile mobile
Page 91: Agile mobile
Page 92: Agile mobile
Page 93: Agile mobile
Page 94: Agile mobile
Page 95: Agile mobile

CONTACT [email protected]