Click to edit Master title style
4/12/17
Intreab cu ridicare de mn ci sunt developer i ci sunt QA
Writing useful automated tests for the Single Page Applications you build
Andrei Sebastian Cmpean, 2017@Andrei_Cimpean
A talk about
things I do to improve feedback
Big JS Frameworks ~2017
Work with a CLI
Have a preferred testing solution
Maximize render performance
Minimize boot time
Components and unidirectional data flow
Things are directly coupled to a multitude of things
Any change to one member, regardless of how trivial, will likely cause many others to require change
Fragile codebase
Where gut feeling worksShitty code
Benefits that come with tests
Easier ramp-up for newcomers on the project or feature
Code reuse is encouraged
Developer uses the code as a client would
Automated testing
Isnt always simple
It's not always clear how to break a problem into small, testable units
Code that is more dependent on interaction than logic can be hard to write tests for
Testing is hard when tests are slow
Every programmer knows they should write tests for their code. Few do.
Noel Rappin Journal 2
Writing automated tests
Writing automated tests for the ~2017 Single Page Apps
Writing useful automated tests for the ~2017 Single Page Apps
Writing useful automated tests for the Single Page Applications you build
Types of tests
That check state
That check behavior
There are other ways of separating tests by type, but well focus only on this one
State verification
Describes a style of testing where you exercise one or many methods of an object and then assert the expected state of the object (and/or collaborators).
Movie movie = a.movie.build();Rental rental =
a.rental.w(movie).build();Store store =
a.store.w(movie).build();rental.start(store);assertTrue(rental.isStarted());assertEquals(
0, store.getAvailability(movie)
);
State verification tests specify the least possible implementation detail, thus they will continue to pass even if the internals of the methods being tested are changed.
Behavior verification
Describes a style of testing where the execution of a method is expected to generate specific interactions between objects.
Movie movie = a.movie.build();Rental rental = a.rental.w(movie).build();Store store = mock(Store.class);when(store.getAvailability(movie)) .thenReturn(1);rental.start(store);assertTrue(rental.isStarted());
Behavior verification tests with minimal collaborators can effectively verify interactions without sacrificing maintainability.
Law of Demeter
Only talk to your immediate friends
Tell, Dont Ask
Rather than asking an object for data and acting on that data, we
should instead tell an object what to do
A team that relies on Behavior verification will likely produce a codebase with few Law of Demeter violations and a focus on Tell, Dont Ask.
The canonical
testing tools:
test doubles,
unit and
acceptance
tests
Test doublesFake objects have incomplete/wrong working implementations
Stubs provide canned answers to calls made during the test
Spies are stubs that also record some information based on how they were called
Mocks are pre-programmed with expectations which form a specification of the calls they are expected to receive.
https://martinfowler.com/bliki/TestDouble.html
Acceptance testingperformed to verify that the product is acceptable to the customer and if it's fulfilling the specified requirements
Unit testingit tests a unit of the program as a whole
Acceptance tests
A test conducted to determine if the requirements of a specification or contract are met
from http://gregbabiars.com/acceptance-testing-a-react-app-using-react-test-utils-pretender-and-rxjs/
Acceptance tests
A test conducted to determine if the requirements of a specification or contract are met
Usually very slow to run
Theres usually a strategy put in place for when to run them
Unit tests
Low-level, focusing on a small part of the software system
From http://learnrubythehardway.org/book/ex47.html
Unit tests
Low-level, focusing on a small part of the software system
Significantly faster than other kinds of tests
Can be run very frequently when programming
Do
Public methods are a contract.
APIs should be tested.
Do
Its OK to write temporary tests for private methods. Implementation
details is subject to change.
Enter
components
Components and unidirectional dataflow
Data down - Actions up
Presentational ContainerBusiness vs. Toolkit
Clear state management
Components make it obvious whats public and whats private
Props/Attributes are public
Everything else is private
Unit test
According to the definition on wikipedia a unit can be an individual method, but it can also be something much larger that likely includes many collaborating classes.Unit testing is an umbrella name for testing at a certain level of abstraction.
Integration testingbetween unit and acceptance testing
test the rendered state of a component (or nested group of components) in isolation from the rest of the app
Enter - Integration Testing
Integration tests
How components behave in regard to DOM Changes
Events
Async
Can be run very frequently when programming
Testing at the right level of abstraction for SPAs
Integration testsare cheap today
Modern JS frameworks Very fast rendering
Fast boot
start fast, remain fast
Powerful machines
From https://www.mutuallyhuman.com/blog/2016/01/22/component-integration-testing-in-ember
Do
Focus on writing integration tests for your components.
Do
Unit tests (for methods) are the exception. Write them only when
they add substantially to confidence.
Templates change a lot
Design changes
Business
Mistake
Bug fixes
This will crash even though the logic didnt.
Do
Avoid matching for class names in integration tests.
Improve your setup!
Automatically cleans the HTML of test tags
Ideally not only used in templatesIf you need to check private attributes
ember-test-selectorsOr alternative for your framework of choice
Template file
Test file
What about methods?
Stop writing method tests that focus on parametersIf you can, and want to, use Typescript or Flow
Alternative, use inline assertions
Stop writing method tests that focus on parametersIf you can, and want to, use Typescript or Flow
Alternative, use inline assertions
Ember.assert('Test for truthiness', obj);Ember.assert('Fail unconditionally');
* In a production build, this method is defined as an empty function (NOP). Uses of this method in Ember itself are stripped from the ember.prod.js build
Inline asserts for rapid feedback
Ember.assert
Use it in appropriate placesLifecycle hooks when new required properties are set
Critical / fragile places
throw new ErrorClean up when building for production
Do
Write integration tests that the component is rendered correctly in
all the contexts.
Do
Write integration tests that all actions are emitted
correctly.
Things developers
say
Its not worth it and Im testing my code before I push to ...Its slowing me down...It wasnt done from the start of the project...The client doesnt pay for itWe have QA
Things developers
say
Its not worth it and Im testing my code before I push to ...Its slowing me down...It wasnt done from the start of the project...The client doesnt pay for itWe have QA ...ITS HARDNOT SOMETHING I USUALLY DO
Gut feeling and bias
Writing tests is slow
Not paid to write tests
Youre not paid to write tests, you just write enough to be confident that your code works as required. Refactoring without having tests is not refactoring, its moving code around.
Not paid to write tests
If I dont typically make a kind of mistake (like setting the wrong variables in a constructor), I dont test for it. I do tend to make sense of test errors, so Im extra careful when I have logic with complicated conditionals.When coding on a team, I modify my strategy to carefully test code that we, collectively, tend to get wrong.https://istacee.wordpress.com/2013/09/18/kent-beck-i-get-paid-for-code-that-works-not-for-tests/
You don't have enough tests (or good enough tests) if you can't confidently change the code.
Do
Evaluate what you and your team get out of tests and dont be afraid
to tweak things around.
Do
Tests are part of the system and they must be maintained to the
same standards as any other part of the system.
TESTS GIVECONFIDENCE
You don't have enough tests (or good enough tests) if you can't confidently change the code.
If you have a lot of tests, a single change to the production code can cause hundreds of tests to require corresponding changes. For example, if you add an argument to a method, every test that calls that method must be changed to add the new argument.
Fragile Test Problem
Fragile Test Problem:As the number of tests grows, a single change to the production code can cause hundreds of tests to require corresponding changes (add an argument to a method, every test must be changed )
SOLID PRINCIPLES
A one-to-one correspondence between production and test code
implies extremely tight coupling.
If the structure of the tests follows the structure of the production code, then the tests are inextricably coupled to the production code
Test and production code evolve in opposite directions.
As the tests get more specific, the production code gets more
generic.
http://blog.cleancoder.com/uncle-bob/2017/03/03/TDD-Harms-Architecture.html?__s=5sgof5whdhfhhnfby3e4
These two streams of code evolve in opposite directions. Programmers refactor tests to become more and more concrete and specific. They refactor the production code to become more and more abstract and general.
highly specific code cannot have a one-to-one correspondence with highly generic code
A test suite that isnt run regularly doesnt have many opportunities to provide positive ROI.
Do
Write a small test, make it pass.
Do
Write in small test/code cycles
Recap
Write in small cycles
Write integration tests for components
Minimize DOM dependency in tests
Only test what makes sense
Refactor tests
Dont pretend you can refactor without tests
Q & A
Would you rather throw away the code and keep the tests or vice-versa?How do you know if your code-base is healthy?
Mocks Arent Stubs, Martin FowlerUnitTest, Martin FowlerIs TDD dead?, Kent Beck, David Heinemeier Hansson, Martin FowlerTDD Harms Architecture, Rober C. Martin"Working Effectively With Unit Tests", Jay FieldsTest Driven Development