Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Architecting your apps for UI Testing

Karumi
September 15, 2016

Architecting your apps for UI Testing

Talk given at NSSpain 2016

Karumi

September 15, 2016
Tweet

More Decks by Karumi

Other Decks in Programming

Transcript

  1. UI PRESENTER USE CASE NAVIGATOR REPOSITORY DATA SOURCE … N

    … COMPOSITION ROOT COMPOSITION ROOT A … N …
  2. UI PRESENTER USE CASE NAVIGATOR REPOSITORY DATA SOURCE … N

    COMPOSITION ROOT COMPOSITION ROOT A … N … …
  3. Navigator Navigates from one screen to another Knows about the

    state of the screen at any given time Handle the presentation of this new screen
  4. CompositionRoot Knows how to instantiate every collaborator of the app

    Knows about the particulars of a collaborator
  5. Presenter Tell the UI what to do Tell Navigators where

    the user wants to go Execute Use Cases KEY point for dependency injection
  6. Screen AppDelegate private func installRootNavigator() { let builder = AppCompositionRoot.Builder()

    appCompositionRoot = builder.with( venueCompositionRoot: VenueCompositionRoot() ).build() navigator = RootNavigator( appCompositionRoot: appCompositionRoot ) navigator.installRootViewController(window!) window?.makeKeyAndVisible() } 1 2 3
  7. DEPENDENCIES AppCompositionRoot class AppCompositionRoot { let venue: VenueCompositionRoot func getInitialViewController()

    -> UINavigationController { let vc = venue.getBestVenuesAroundViewController() return UINavigationController(rootViewController: vc) } }
  8. DEPENDENCIES VenueCompositionRoot func getBestVenuesAroundViewController() -> UIViewController { let vc =

    BestVenuesAroundYouViewController() vc.venuesAroundYouPresenter = BestVenuesAroundYouPresenter( ui: vc, getBestPlacesAroundYouUseCase: getPlacesAroundYouUseCase(), getUserLocationUseCase: getUserLocationUseCase(), navigator: getVenueListNavigator() ) return vc }
  9. TAP

  10. Screen BestVenuesAroundYouViewController func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) { guard

    let venue = ds.venue(atIndexPath: indexPath) else { return } venuesAroundYouPresenter.venueSelected(venue) }
  11. DEPENDENCIES VenueListNavigator func goTo(venueDetail venue: VenueViewModel) { let vc =

    appCompositionRoot.venue.getVenueDetailViewController( forVenue: venue ) currentNavigationController?.pushViewController( vc, animated: true ) }
  12. UI PRESENTER USE CASE NAVIGATOR REPOSITORY DATA SOURCE … N

    … COMPOSITION ROOT COMPOSITION ROOT A … N …
  13. TEST AppDelegateForTests func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?)

    -> Bool { window = UIWindow(frame: UIScreen.mainScreen().bounds )! window.backgroundColor = .whiteColor() window.makeKeyAndVisible() window.rootViewController = UINavigationController() return true }
  14. TEST BaseUITest func openViewController() { let appCompositionRoot = getTestingAppCompositionRoot( baseAppCompositionRoot

    ) rootNavigator = RootNavigator( appCompositionRoot: appCompositionRoot ) presentViewController( keyWindow, navigator: rootNavigator, appCompositionRoot: appCompositionRoot ) } 1 2 3
  15. TEST BestVenuesAroundYouViewControllerTests class BestVenuesAroundYouViewControllerTests: BaseUITestCase { private var stubVenueListNavigator: StubVenueListNavigator!

    private var getUserLocation: StubGetUserLocationUseCase! private var getBestPlacesAroundYou: StubGetBestPlacesAroundYouUseCase! override func setUp() { super.setUp() getUserLocation = StubGetUserLocationUseCase() getBestPlacesAroundYou = StubGetBestPlacesAroundYouUseCase() stubVenueListNavigator = StubVenueListNavigator() }
  16. TEST BestVenuesAroundYouViewControllerTests override func getTestingAppCompositionRoot(compositionRoot: AppCompositionRoot) -> AppCompositionRoot { return

    AppCompositionRoot.Builder() .with(venueCompositionRoot: getVenueCompositionRoot()) .build() } private func getVenueCompositionRoot() -> VenueCompositionRoot { let venueCompositionRoot = TestingVenueCompositionRoot() venueCompositionRoot.stubGetUserLocation = getUserLocation venueCompositionRoot.stubGetBestPlacesAroundYou = getBestPlacesAroundYou venueCompositionRoot.stubVenueListNavigator = stubVenueListNavigator return venueCompositionRoot }
  17. TEST func getGetUserLocationUseCase() -> GetUserLocationUseCase { return GetUserLocation( gps: getGPS(),

    repository: getVenueDataSource() ) } func getGetUserLocationUseCase() -> GetUserLocationUseCase { return stubGetUserLocationUseCase } VenueCompositionRoot TestingVenueCompositionRoot
  18. TEST BestVenuesAroundYouViewControllerTests func testLoadingIndicatorIsVisibleWhenLoadingVenues() { givenWeAreFetchingUsersLocation() openViewController() waitForViewWithLocalizedAccessibilityLabel(.Loading) } override

    func presentViewController(window: UIWindow, navigator: RootNavigator, appCompositionRoot: AppCompositionRoot) { presentViewController( appCompositionRoot.venue.getBestVenuesAroundViewController() ) }
  19. TEST BestVenuesAroundYouViewControllerNavigationTests override func presentViewController(window: UIWindow, navigator: RootNavigator, appCompositionRoot: AppCompositionRoot)

    { navigator.installRootViewController(window) } override func getTestingAppCompositionRoot(compositionRoot: AppCompositionRoot) -> AppCompositionRoot { return AppCompositionRoot.Builder(compositionRoot: compositionRoot) .with(venueCompositionRoot: getVenueCompositionRoot()) .build() } private func getVenueCompositionRoot() -> VenueCompositionRoot { let venueCompositionRoot = TestingVenueCompositionRoot() venueCompositionRoot.stubGetUserLocationUseCase = getUserLocationUseCase venueCompositionRoot.stubGetBestPlacesAroundYouUseCase = getBestPlacesAroundYouUseCase venueCompositionRoot.stubGetVenueDetailsUseCase = getVenueDetailsUseCase return venueCompositionRoot } private func getVenueCompositionRoot() -> VenueCompositionRoot { let venueCompositionRoot = TestingVenueCompositionRoot() venueCompositionRoot.stubGetUserLocation = getUserLocation venueCompositionRoot.stubGetBestPlacesAroundYou = getBestPlacesAroundYou venueCompositionRoot.stubVenueListNavigator = stubVenueListNavigator return venueCompositionRoot } BestVenuesAroundYouViewControllerTests
  20. TEST BestVenuesAroundYouViewControllerNavigationTests func testNavigatesToVenueDetailWhenUserTapsOnVenue() { getVenuesUseCase.givenThereWillBeVenues() let topVenue = getVenuesUseCase.getTopVenue()

    getVenueDetailsUseCase.venue = topVenue openViewController() tapTopVenue() expectTitle(ofVenue: topVenue, toBeVisible: true) } GIVEN WHEN THEN