BDD DEVit

BDD DEVit

15633e65c96546d830fb84ee7fe5db9c?s=128

Pawel Dudek

June 11, 2018
Tweet

Transcript

  1. Behavior Driven Development Paweł Dudek

  2. None
  3. Behavior Driven Development

  4. What is a unit test? 4

  5. A method by which individual units of source code, sets

    of one or more program modules together with associated control data, usage procedures, and operating procedures are tested to determine if they are fit for use. --Kolawa, Adam; Huizinga, Dorota (2007) 5
  6. Um, what? 6

  7. A method by which individual units of source code, sets

    of one or more program modules together with associated control data, usage procedures, and operating procedures are tested to determine if they are fit for use. --Kolawa, Adam; Huizinga, Dorota (2007) 7
  8. What is an app? 8

  9. An app is a set of behaviors created by a

    programmer and expected by the user. 9
  10. We, humans, have a limited cognition. 10

  11. We can’t always ‘load’ all of the code of our

    app into our memory. 11
  12. This means that we can, by accident, change the behavior

    of the app. 12
  13. Preserving behavior of software systems is hard. 13

  14. Enter unit tests. 14

  15. Unit test is a failsafe to make sure app behavior

    is preserved. 15
  16. Test Driven Development 16

  17. Tests drive the way you code 17

  18. Always write test first 18

  19. Tests influence architecture of your app 19

  20. Tests tell you whether your design became too complex 20

  21. There is no such thing as untestable behavior Only untestable

    code 21
  22. Have to simulate behavior of your dependency dependency dependency? 22

  23. Need to fake seven objects? 23

  24. Need to call five functions to simulate a behavior? 24

  25. Hard to specify clear requirements? 25

  26. Overcomplicated design 26

  27. Thinked-through design 27

  28. First consumer of your API 28

  29. There is no such thing as untestable behavior Only untestable

    code 29
  30. What is testable code? 30

  31. Testable code == Good Architecture 31

  32. What is good architecture? 32

  33. SOLID Object-Oriented Design Sandi Metz https://www.youtube.com/watch?v=v-2yFMzxqwU 33

  34. Behavior Driven Development Test Driven Development 34

  35. What's the difference? 35

  36. BDD aims to improve certain aspects of TDD 36

  37. BDD tries to help you know what to test 37

  38. When writing tests don’t think ‘tests’ 38

  39. Think about ‘behaviors’ 39

  40. Think about examples how your object should behave 40

  41. Objects behavior == Public interface 41

  42. You should be only testing public interface of your objects

    Not internal implementation 42
  43. Work outside-in 43

  44. Ubiquitous language 44

  45. Quick & Nimble Swift BDD Frameworks 45

  46. class DolphinSpec: QuickSpec { override func spec() { it("is friendly")

    { expect(Dolphin().isFriendly).to(beTruthy()) } it("is smart") { expect(Dolphin().isSmart).to(beTruthy()) } } }
  47. class DolphinSpec: QuickSpec { override func spec() { it("is friendly")

    { expect(Dolphin().isFriendly).to(beTruthy()) } it("is smart") { expect(Dolphin().isSmart).to(beTruthy()) } } }
  48. describe("a dolphin") { describe("its click") { it("is loud") { let

    click = Dolphin().click() expect(click.isLoud).to(beTruthy()) } it("has a high frequency") { let click = Dolphin().click() expect(click.hasHighFrequency).to(beTruthy()) } } }
  49. describe("a dolphin") { describe("its click") { it("is loud") { let

    click = Dolphin().click() expect(click.isLoud).to(beTruthy()) } it("has a high frequency") { let click = Dolphin().click() expect(click.hasHighFrequency).to(beTruthy()) } } }
  50. describe("a dolphin") { describe("its click") { it("is loud") { let

    click = Dolphin().click() expect(click.isLoud).to(beTruthy()) } it("has a high frequency") { let click = Dolphin().click() expect(click.hasHighFrequency).to(beTruthy()) } } }
  51. describe("a dolphin") { var dolphin: Dolphin! beforeEach { dolphin =

    Dolphin() } describe("its click") { var click: Click! beforeEach { click = dolphin.click() } it("is loud") { expect(click.isLoud).to(beTruthy()) } it("has a high frequency") { expect(click.hasHighFrequency).to(beTruthy()) } } }
  52. describe("a dolphin") { var dolphin: Dolphin! beforeEach { dolphin =

    Dolphin() } describe("its click") { var click: Click! beforeEach { click = dolphin.click() } it("is loud") { expect(click.isLoud).to(beTruthy()) } it("has a high frequency") { expect(click.hasHighFrequency).to(beTruthy()) } } }
  53. describe("a dolphin") { var dolphin: Dolphin! beforeEach { dolphin =

    Dolphin() } describe("its click") { var click: Click! beforeEach { click = dolphin.click() } it("is loud") { expect(click.isLoud).to(beTruthy()) } it("has a high frequency") { expect(click.hasHighFrequency).to(beTruthy()) } } }
  54. Real world example 54

  55. class PhotoUploadViewController: UIViewController { let photoUploader: PhotoUploader required init(photoUploader: PhotoUploader)

    { self.photoUploader = photoUploader super.init(nibName: nil, bundle: nil) navigationItem.rightBarButtonItem = UIBarButtonItem( title: "Done", target: self, action: #selector(PhotoUploadViewController.onTap(_:))) } @objc func onTap(_ item: UIBarButtonItem?) { photoUploader.upload(photo: UIImage()) { success in print("\(success)") } } }
  56. protocol PhotoUploader { func upload(photo: UIImage, completion: (_ success: Bool)

    -> Void) } class MockPhotoUploader: PhotoUploader { fileprivate(set) var photoUploadCalled: Bool = false func upload(photo: UIImage, completion: (_ success: Bool) -> Void) { self.photoUploadCalled = true } }
  57. var sut: PhotoUploadViewController! var mockPhotoUploader: MockPhotoUploader! beforeEach { mockPhotoUploader =

    MockPhotoUploader() sut = PhotoUploadViewController(photoUploader: mockPhotoUploader) } afterEach { sut = nil }
  58. // non-bdd describe("right bar button item") { var rightBarButtonItem: UIBarButtonItem?

    beforeEach { rightBarButtonItem = sut.navigationItem.rightBarButtonItem } it("should have a target") { let actual = rightBarButtonItem?.target as? PhotoUploadViewController expect(actual).to(equal(sut)) } it("should have an action") { let expected = #selector(PhotoUploadViewController.onTap(_:)) expect(rightBarButtonItem?.action).to(equal(expected)) } }
  59. // non-bdd describe("right bar button item action") { beforeEach {

    let rightBarButtonItem = sut.navigationItem.rightBarButtonItem sut.onTap(rightBarButtonItem) } it("should tell the photo uploader to upload photo") { expect(fakePhotoUploader.photoUploadCalled).to(beTruthy()) } }
  60. // bdd describe("right bar button item") { var rightBarButtonItem: UIBarButtonItem?

    beforeEach { rightBarButtonItem = sut.navigationItem.rightBarButtonItem } describe("when it is tapped") { beforeEach { rightBarButtonItem?.specSimulateTap() } it("should tell the photo uploader to upload photo") { expect(fakePhotoUploader.photoUploadCalled).to(beTruthy()) } } }
  61. BDD - recap » Tests influence your architecture » No

    such thing as untestable behavior » Think examples/behaviors, not tests » Don’t test implementation, work outside-in » Use ubiquitous language to make examples easily understandable 61
  62. Further read: » https://speakerdeck.com/paweldudek/bdd-devit » https://github.com/paweldudek/good-tdd-stuff » https://github.com/paweldudek/bdd-presentation Getting in

    touch: » @eldudi » pawel@dudek.mobi 62