Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Hyper-pragmatic Pure FP testing with distage-testkit

139 views

Published on

Having a proper test suite can turn ongoing application maintenance and development into pure joy – the best tests check meaningful properties, not the implementation details, and hold no impliict assumptions about their test environment - every test case must be self-contained and portable. To ensure that tests are free of implementation details and environment dependency, we may simply run them in a different test environment, with different implementations of components. But the boileplate and manual work involved in rewiring components, writing hardcoded fixtures and setting up different test environments make this very hard to do at scale. To tackle this problem we've created distage & distage-testkit, distage-testkit gives you the following superpowers:

* ability to easily swap out individual components or entire test environments

* principled & leak-free control of global resources for integration testing – docker containers, DBs, DDLs

* execute effects or allocate resources per-test, e.g. generate random fixtures per-test

* first-class testing of functional effects

* write tests as lambdas – access test fixtures via parameters or ZIO Environment

...and more! We'll also discuss general testing practices and what really distinguishes good tests from great tests.

Published in: Software
  • Be the first to comment

  • Be the first to like this

Hyper-pragmatic Pure FP testing with distage-testkit

  1. 1. Hyperpragmatic pure FP testing with distage-testkit 1/31 Hyperpragmatic pure FP testing with distage-testkit Functional Scala 2019 Septimal Mind Ltd team@7mind.io 1 / 31
  2. 2. Hyperpragmatic pure FP testing with distage-testkit Tests and Test Taxonomies 2/31 Not all the tests are equal Tests are important. We know that. Tests are the simplest way to define and verify important contracts. And contracts are crucial for project maintainability and viability. We write tests. A lot of. But . . . some tests prove themselves useful and some do not. 2 / 31
  3. 3. Hyperpragmatic pure FP testing with distage-testkit Tests and Test Taxonomies 3/31 Not all the tests are equal Which tests are good and which are bad? 3 / 31
  4. 4. Hyperpragmatic pure FP testing with distage-testkit Tests and Test Taxonomies 4/31 Bad test criterias Bad tests are: ◮ Slow, ◮ Unstable: they fail randomly, ◮ Nonviable: they don’t survive refactorings, ◮ Demanding: they require complex preconditions to be met: external services up and running, fixtures loaded, etc, etc, ◮ Incomprehensible: they signal about a problem but don’t help us to localize the cause. 4 / 31
  5. 5. Hyperpragmatic pure FP testing with distage-testkit Tests and Test Taxonomies 5/31 We spend more resources to write and maintain bad tests than the value they bring us. 5 / 31
  6. 6. Hyperpragmatic pure FP testing with distage-testkit Tests and Test Taxonomies 6/31 How may we make our tests better? 6 / 31
  7. 7. Hyperpragmatic pure FP testing with distage-testkit Tests and Test Taxonomies 7/31 Let’s ditch Unit/Functional/Integration trinity. . . . . . and introduce some new terminology 7 / 31
  8. 8. Hyperpragmatic pure FP testing with distage-testkit Tests and Test Taxonomies 8/31 Test Taxonomy: Encapsulation Axis Let’s say that every test falls under one of the following categories: 1. Blackbox tests check just interfaces not knowing anything about implementations behind them, 2. Whitebox tests may know about implementations and check them directly, sometimes even breaking into some internal state to verify if it conforms to test expectations. 8 / 31
  9. 9. Hyperpragmatic pure FP testing with distage-testkit Tests and Test Taxonomies 9/31 Test Taxonomy: Isolation Axis Let’s say that every test falls under one of the following categories: ◮ Atomic tests check just one “unsplittable” software component, ◮ Group tests check multiple software components, ◮ Communication tests communicate with outer world (databases, API providers, etc, etc). 9 / 31
  10. 10. Hyperpragmatic pure FP testing with distage-testkit Tests and Test Taxonomies 10/31 You may extend and modify this Test Taxonomy as it would be convenient for you. More about test taxonomies: https://blog.7mind.io/constructive-test-taxonomy.html 10 / 31
  11. 11. Hyperpragmatic pure FP testing with distage-testkit Tests and Test Taxonomies 11/31 Test Taxonomy: Why So? According to our experience the best tests are Blackbox tests with Atomic or Group Isolation Level. This makes sense: such tests are fast and refactoring-resilient. 11 / 31
  12. 12. Hyperpragmatic pure FP testing with distage-testkit Tests and Test Taxonomies 12/31 Communication tests But in real projects most of the tests fall under Communication category (“Integration” tests). Why? 1. Engineers want to test The Whole Thing, 2. It’s hard to separate components, 3. etc, etc. . . 12 / 31
  13. 13. Hyperpragmatic pure FP testing with distage-testkit Tests and Test Taxonomies 13/31 Communication tests can be more useful We may replace integration components with Dummies1. This way we may turn Communication tests into Group or Atomic2 1 people also call them “Fakes”, “in-memory implementations” or “Mocks” 2 this statement is valid for Blackbox tests only 13 / 31
  14. 14. Hyperpragmatic pure FP testing with distage-testkit Dual Test Tactic 14/31 Dual Test Tactic The same test scenario executed with both Production and Dummy implementations of integration components is beneficial: 1. We can test business logic quickly, without any interference, 2. We still able to verify business logic behaviour with “real” integrations, 3. Dual Test Tactic enforces us to follow LSP and design better. Refactorings are crucial for long-term health of the project. Blackbox tests enable refactorings. Dual Test Tactic drastically reduces the price of refactorings. 14 / 31
  15. 15. Hyperpragmatic pure FP testing with distage-testkit Dual Test Tactic 15/31 Dual Test Tactic: ideas 1. Ignore Communication tests in case their dependencies are unsatisfied (service unavailable), don’t fail, 2. Avoid automatic “Mocks”, they prevent encapsulation, 3. Never run heavy dependencies in-process ◮ don’t bring whole Kafka or Cassandra into the classpath. PLEASE 15 / 31
  16. 16. Hyperpragmatic pure FP testing with distage-testkit Dual Test Tactic 16/31 Dual Test Tactic: The Main Issue It’s easy to setup test dependencies while working with Dummies But you have to do things differently for Production dependencies. We have to take care of: 1. Resource acquisition and Cleanups, 2. Speed, 3. Memoization and resource reuse, 4. Interference, 5. . . . 16 / 31
  17. 17. Hyperpragmatic pure FP testing with distage-testkit Dual Test Tactic 17/31 Dual Test Tactic: dummy repositories testcase make[UserRepo] make[UserService] make[AccountsRepo] make[AccountsService] run[MyTestCase] run[AnotherTestCase] 17 / 31
  18. 18. Hyperpragmatic pure FP testing with distage-testkit Dual Test Tactic 18/31 Dual Test Tactic: production repositories testcase Setup Execute Cleanup probe database port make[DbDriver] setup users table setup accounts table make[UserRepo] make[AccountsRepo] remove users table close driver remove accounts table make[UserService] make[AccountsService] run[MyTestCase]run[AnotherTestCase] 1. Order 2. How to avoid unneccessary job? 2.1 Memoize resources?.. 2.2 In a singleton?.. 2.3 When we close resources?.. 2.4 On JVM shutdown?.. Oops, SBT. . . 2.5 Disambiguation (same class, different parameters)?.. 3. Resource deallocation 3.1 . . . even after a failure 3.2 Order! 4. Other integrations, e.g. run Dockers 4.1 . . . and await until they open ports 4.2 . . . and stop them after the tests 5. Configs 18 / 31
  19. 19. Hyperpragmatic pure FP testing with distage-testkit Dual Test Tactic 19/31 Dual Test Tactic: Real testcase steps ◮ Integration points stack together ◮ . . . and make the problem notably hard ◮ Manual wiring is hard to maintain ◮ . . . and suffers from combinatoric explosion of possible code paths ◮ Cake pattern doesn’t make much difference ◮ Conventional DI frameworks fail It’s hard to setup variable contexts. 19 / 31
  20. 20. Hyperpragmatic pure FP testing with distage-testkit Dual Test Tactic 20/31 Dual Test Tactic may be very pricy under usual circumstances. 20 / 31
  21. 21. Hyperpragmatic pure FP testing with distage-testkit Dual Test Tactic 21/31 Can we make it cheap? 21 / 31
  22. 22. Hyperpragmatic pure FP testing with distage-testkit Dual Test Tactic 22/31 Yes. 22 / 31
  23. 23. Hyperpragmatic pure FP testing with distage-testkit Dual Test Tactic 23/31 The Goal We want to write code like this and never care about setting things up: 1 class JustATest[F[+_, +_]] { 2 "service" must { 3 "do something" in { 4 (users: UserService[F], accounts: AccountingService[F]) => 5 for { 6 user <- users.create() 7 balance <- accounts.getBalance(user) 8 } yield { 9 assert(balance == 0) 10 } 11 } 12 } 13 } 14 15 object JustATestZioProd extends JustATest[zio.IO] with Prod 16 object JustATestZioDummy extends JustATest[zio.IO] with Dummy 23 / 31
  24. 24. Hyperpragmatic pure FP testing with distage-testkit Dual Test Tactic 24/31 dist✪ge is a Dependency Injection mechanism for Scala But it lacks negative traits of a typical DI thingy. . . . . . and has many unique properties. . . . and it’s blazing fast. You may call it a module system for Scala. . . . . . with automatic garbage-collecting solver 24 / 31
  25. 25. Hyperpragmatic pure FP testing with distage-testkit Dual Test Tactic 25/31 distage 1. Supports FP, wires Resources, Effects, ZIO Environments. . . 2. transparent and predictable ◮ first plan then do ◮ test the outcome without effect execution! ◮ compile-time checks and tests 3. no scala-reflect nor Java reflection1, ◮ ScalaJS support is coming 4. is non-invasive. ◮ You can add it to your project keeping business logic intact. . . ◮ . . . and remove it. 5. is not an ad-hoc thing, it has strong theory behind. 1 Since version 0.10.0, see https://blog.7mind.io/lightweight-reflection.html 25 / 31
  26. 26. Hyperpragmatic pure FP testing with distage-testkit Dual Test Tactic 26/31 Docker support in distage While we develop and test we may need our integrations up and running. . . . . . We have docker-compose for that. . . But manual rituals are annoying and Compose is imperfect (wait until service opens port? Hah) Container orchestration is not easy. But. . . We made a distage extension allowing to get rid of Compose in most of the cases. It can run test containers, reuse and shutdown them. And it can await until the service is ready. 26 / 31
  27. 27. Hyperpragmatic pure FP testing with distage-testkit Dual Test Tactic 27/31 Let’s look at a real example. . . Source code: https://github.com/7mind/distage-example 27 / 31
  28. 28. Hyperpragmatic pure FP testing with distage-testkit Dual Test Tactic 28/31 distage performs optimal ahead of time planning. It doesn’t do any unnecessary job. 28 / 31
  29. 29. Hyperpragmatic pure FP testing with distage-testkit Dual Test Tactic 29/31 One More Thing: Roles distage allow you to fuse microservices into “flexible monoliths”. We may: 1. Develop services (Roles) separately, even in a multirepo, 2. Build a single Docker image with multiple Roles in it, 3. Run several Roles within one process ◮ We define roles we want to start as commandline parameters 4. ⇒ higher computation density, savings on infrastructure, 5. ⇒ substantial development simplification ◮ full environment can be started on a low-end machine ◮ with just one command 29 / 31
  30. 30. Hyperpragmatic pure FP testing with distage-testkit Dual Test Tactic 30/31 distage-framework is the most productive way to write maintainable pure functional applications with ZIO. (And any other monad) distage-testkit is the best way to make your tests performant and reliable. distage is adopted by several different companies and tested by two years of production usage. 30 / 31
  31. 31. Hyperpragmatic pure FP testing with distage-testkit Dual Test Tactic 31/31 Thank you for your attention distage website: https://izumi.7mind.io Septimal Mind is an Irish software consultancy and R&D Company We’re looking for clients, contributors, adopters and colleagues ;) Contact: team@7mind.io Github: https://github.com/7mind Slides: https://github.com/7mind/slides Follow us on Twitter https://twitter.com/shirshovp https://twitter.com/kai_nyasha 31 / 31

×