Testes - A que será que se destina?

Testes - A que será que se destina?

Uma talk baseada em exemplos reais de implementações de testes, a partir de experências práticas e conceitos teóricos. Os objetivos são: encorajar a implementação da cultura de testes; Para aqueles que já o fazem, aprimorar a qualidade de testes implantados; E que o conteúdo apresentado seja orientador para os que se interessem pelo tema.

A928e0a8375d93d165ad90bb860c05d9?s=128

Ronan Rodrigo Nunes

November 09, 2019
Tweet

Transcript

  1. Testes: A que será que se destina? Breve história sobre

    testes, boas e más práticas no ecossistema Apple Ronan Rodrigo Nunes
  2. Arqueologia

  3. None
  4. …1956 Debugging-oriented Sem distinção entre testes e debugging

  5. 1957 ~ 78 Demonstration-oriented Garantir o atendimento de requisitos de

    software
  6. 1979 ~ 82 Destruction-Oriented Detectar falhas de implementações

  7. 1983 ~ 87 Evaluation-Oriented Detectar falhas nos requisitos e no

    design e implementação
  8. 1988… Prevention-Oriented Evitar falhas nos requisitos, design e implementação

  9. 2003 Xcode 1.0 Sem tool para testes

  10. 2005 Xcode 2.1 Primeira versão com suporte a testes unitários

    (OCUnit)
  11. 2007 Xcode 3.0 Primeiro com SDK do iOS

  12. 2013 Xcode 5.0 Substituição do OCUnit por XCTest

  13. 2015 Xcode 7.0 Primeiro com XCUITest

  14. Cultura

  15. None
  16. Meu código funciona perfeitamente, por que eu testaria? “

  17. Não vejo benefício; “

  18. Até APP com testes tem bugs “

  19. Não sei como, nem o que testar. “

  20. Não temos tempo “

  21. É difícil e complicado “

  22. Como melhorar a cultura de testes do meu time? “

    http://mobster.cc
  23. O que testar

  24. Pirâmide de testes

  25. Unit Integration UI Mais Isolamento Mais Integração Rápido Lento

  26. Boas práticas & Smells & Armadilhas

  27. func test_primaryButtonTapped_doesRouteToFullSheet() { // given XCTAssertTrue(router.routeToFullSheetCallCount == 0) // when

    interactor.primaryButtonTapped() // then XCTAssertTrue(router.routeToFullSheetCallCount == 1) } ✘
  28. func test_primaryButtonTapped_doesRouteToFullSheet() { XCTAssertTrue(router.routeToFullSheetCallCount == 0) interactor.primaryButtonTapped() XCTAssertTrue(router.routeToFullSheetCallCount == 1)

    } ✘
  29. func test_primaryButtonTapped_doesRouteToFullSheet() { interactor.primaryButtonTapped() XCTAssertTrue(router.routeToFullSheetCallCount == 1) } ✘

  30. func test_primaryButtonTapped_doesRouteToFullSheet() { interactor.primaryButtonTapped() XCTAssertEqual(router.routeToFullSheetCallCount, 1) } ✔

  31. func test_startReport_doesRouteToReportFlow() { interactor.startReport() XCTAssertEqual(router.routeToReportFlowCallCount, 1) } ✔

  32. func test_allByMonth_existingMonth_callCompletionWithItems() { var expectedGroupedFoods: [GroupedFoods]? // ... guard let

    expectedGroupedFoods = expectedGroupedFoods, firstGroup = expectedGroupedFoods.first else { XCTFail("empty expectedGroupedFoods") } XCTAssertFalse(firstGroup.foods.isEmpty) } ✘
  33. func test_allByMonth_existingMonth_callCompletionWithItems() { var expectedGroupedFoods: [GroupedFoods]? // ... XCTAssertFalse(expectedGroupedFoods!.first!.foods.isEmpty) }

  34. func test_allByMonth_existingMonth_callCompletionWithItems() { var expectedGroupedFoods: [GroupedFoods]? // ... if let

    expectedGroupedFoods = expectedGroupedFoods { if let firstGroup = expectedGroupedFoods.first { XCTAssertFalse(firstGroup.foods.isEmpty) } } } ✘
  35. func test_allByMonth_existingMonth_callCompletionWithItems() { var expectedGroupedFoods: [GroupedFoods]? // ... XCTAssertEqual(expectedGroupedFoods?.first?.foods.isEmpty, false)

    XCTAssertEqual(expectedGroupedFoods?.first?.foods.count, 4) } ✔
  36. func test_allByMonth_existingMonth_callCompletionWithItems() { var expectedGroupedFoods: [GroupedFoods]? let month = MonthGatewayFactory.make().month(number:

    1) gateway.all(byMonth: month) { expectedGroupedFoods = $0.data } XCTAssertEqual(expectedGroupedFoods?.isEmpty, false) } ✘
  37. func test_allByMonth_existingMonth_callCompletionWithItems() { var expectedGroupedFoods: [GroupedFoods]? let month = MonthGatewayFactory.make().month(number:

    1) gateway.all(byMonth: month) { expectedGroupedFoods = $0.data } XCTAssertEqual(expectedGroupedFoods?.isEmpty, false) } ✔
  38. func test_finishReport_completeFlow() { var completed = false interactor.waitForCompletion().subscribe { _

    in completed = true } .disposed(by: disposeBag) interactor.finish() XCTAssertTrue(completed) } ✘
  39. func test_finishReport_completeFlow() { var completed = false onCompleteFlow(completed = true)

    interactor.finish() XCTAssertTrue(completed) } func onCompleteFlow(_ fn: @escaping @autoclosure () -> ()) { interactor.waitForCompletion() .subscribe { _ in fn() } .disposeOnTearDown(testCase: self) } ✔
  40. class ReportTripInteractorTests: XCTestCase class ReportTripInteractor_StartTripTests: ReportTripInteractorTests class ReportTripInteractor_FinishingTripTests: ReportTripInteractorTests class

    ReportTripInteractor_SearchingTripTests: ReportTripInteractorTests class ReportTripInteractor_WaintingTripTests: ReportTripInteractorTests ✔
  41. func test_start_validInteractor_createEventAtStream() { let expectedResponse = Response(uuid: "id") shareService.fetchHandler =

    { _ in .just(expectedResponse) } worker.start(interactor) someStream.dataSubject .subscribe(onNext: { eventResponse in XCTAssertEqual(expectedResponse, eventResponse) }) .disposed(by: disposeBag) } ✘
  42. class Worker { func start(_ interactor: AnyInteractor) { someObservable .subscribe(someStream.dataSubject)

    .disposeOnStop(self) } } .subscribe(someStream.dataSubject)
  43. class Worker { func start(_ interactor: AnyInteractor) { someObservable .disposeOnStop(self)

    } }
  44. func test_start_validInteractor_createEventAtStream() { let expectedResponse = Response(uuid: "id") shareService.fetchHandler =

    { _ in .just(expectedResponse) } var eventResponse: Response? someStream.dataSubject .subscribe(onNext: { eventResponse = $0 }) .disposed(by: disposeBag) worker.start(interactor) XCTAssertEqual(expectedResponse, eventResponse) } ✔
  45. final class ListFoodPresenterViewControllerTests: XCTestCase { private let bindable: ListFoodTableViewControllerBindMock! private

    let presenter: ListFoodPresenterViewController! override func setUp() { super.setUp() bindable = ListFoodTableViewControllerBindMock() presenter = ListFoodPresenterViewController() presenter.bindable = bindable } } !
  46. final class ListFoodPresenterViewControllerTests: XCTestCase { private let bindable = ListFoodTableViewControllerBindMock()

    private let presenter = ListFoodPresenterViewController() override func setUp() { super.setUp() presenter.bindable = bindable } } ✔
  47. final class ListFoodPresenterViewControllerTests: XCTestCase { private let bindable = ListFoodTableViewControllerBindMock()

    private lazy var presenter: ListFoodPresenterViewController = { let presenter = ListFoodPresenterViewController() presenter.bindable = bindable return presenter }() } ✔
  48. Obrigado

  49. Obrigado ronanrodrigo.com