SlideShare a Scribd company logo
1 of 41
TESTING
Tomek Polanski
tpolansk
WHY?
WHEN?
HOW?
“Too much time pressure with making
visible changes.
Customer doesn't appreciate tests enough.”
“To make iterations as fast as possible I
would not use tests for prototypes or early
MVPs.”
“Specs are too volatile, tests would just
need to be updated constantly.”
“Writing tests is hard, they might be
difficult to understand.”
“Nobody else in the project uses them.
They weren't done or were broken when I
got involved.”
Time and budget
“Too much time
pressure with making
visible changes”
Instant changes Return on investment
vs
Speed
“Not for prototypes
or early MVPs”
Time
Progress
Prototype
Minimum
Viable
Product
Lovable
by Henrik Kniberg
Constant ChangeThe
“Specs are too
volatile”
Programming is hard
https://deeguns.files.wordpress.com/2013/07/computerman.jpg
urbanattitude.fr/wp-content/uploads/2015/03/BER_08.jpg
Architecture
“Tests are hard and
difficult to understand”
Maintenance
“Missing/broken
tests”
What should unit tests
look like?
Fast
Reliable
Simple to understand
@Test
public void get_whenElementExists() {
List<String> list = Collections.singletonList(DEFAULT);
assertThat(get(list, 0)).isEqualTo(DEFAULT);
}
@Test
public void get_whenIndexTooBig_returnNull() {
List<String> list = Collections.singletonList(DEFAULT);
assertThat(get(list, 1)).isNull();
}
@Test
public void get_whenIndexTooSmall_returnNull() {
List<String> list = Collections.singletonList(DEFAULT);
assertThat(get(list, -1)).isNull();
}
Simple to understand?
Arrange Act Assert
@Test
public void insertBuilder_withTable_withColumn_doesNotThrow() {
new Builder().table(TABLE)
.addColumn(COLUMN1)
.build();
}
@Test(expected = IllegalStateException.class)
public void insertBuilder_withoutColumns_throwsException() {
new Builder().table(TABLE)
.build();
}
Similar tests
Test setup
@Test
public void test() {
List<Language> list = Arrays.asList(GERMAN, ENGLISH);
Mockito.when(mDataModel.getSupportedLanguages())
.thenReturn(list);
Mockito.when(mDataModel.getGreetingByLanguageCode(LanguageCode.EN))
.thenReturn("Hi!");
// The rest of the test
}
Arrange builder
class ArrangeBuilder {
ArrangeBuilder withLanguages(Language... languages) {
Mockito.when(mDataModel.getSupportedLanguages())
.thenReturn(Arrays.asList(languages));
return this;
}
ArrangeBuilder withGreetings(LanguageCode code, String greeting) {
Mockito.when(mDataModel.getGreetingByLanguageCode(code))
.thenReturn(greeting);
return this;
}
}
@Test
public void test() {
List<Language> list = Arrays.asList(GERMAN, ENGLISH);
Mockito.when(mDataModel.getSupportedLanguages())
.thenReturn(list);
Mockito.when(mDataModel.getGreetingByLanguageCode(LanguageCode.EN))
.thenReturn("Hi!");
// The rest of the test
}
@Test
public void test() {
new ArrangeBuilder()
.withLanguages(GERMAN, ENGLISH)
.withGreetings(LanguageCode.EN, "Hi!");
// The rest of the test
}
Arrange builder
Simple to write
Is it all?
Do I have enough tests?
static boolean isEven(int number) {
return number % 2 == 0;
}
static boolean isEven(int number) {
return number % 2 == 0 ? true : false;
}
What’s the code coverage?
@Test
public void isTwoEven() {
assertThat(isEven(2))
.isTrue();
}
static boolean isEven(int number) {
if ( number % 2 == 0 ) {
return true;
} else {
return false;
}
}
What’s the code coverage?
Observable<Boolean> isEven(int number) {
return Observable.just(number)
.map(num -> num % 2 == 0);
}
@Test
public void isTwoEven() {
TestSubscriber<Boolean> ts = new TestSubscriber<>();
isEven(2).subscribe(ts);
ts.assertValue(true);
}
@Test
public void isTwoEven() {
TestSubscriber<Boolean> ts = new TestSubscriber<>();
isEven(2).subscribe(ts);
}
Do I have too many tests?
Do I have too much code?
public class Translation {
public final String mText;
public Translation(String text) {
mText = text;
}
public String text() {
return mText;
}
} @AutoValue
public abstract class Translation {
public abstract String text();
public static Translation create(String text) {
return new AutoValue_Translation(text);
}
}
. public class Translation {
private final String mText;
public Translation(String text) {
mText = text;
}
public String text() {
return mText;
}
@Override
public int hashCode() {
return mText != null ? mText.hashCode() : 0;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Translation that = (Translation) o;
return mText != null
? mText.equals(that.mText)
: that.mText == null;
}
}
. @Test
public void valueEquality() {
String value = "text";
Translation first = Translation.create(value);
Translation second = Translation.create(value);
assertThat(first).isEqualTo(second);
}
@AutoValue
public abstract class Translation {
public abstract String text();
public static Translation create(String text) {
return new AutoValue_Translation(text);
}
@Override
public int hashCode() {
// ...
}
@Override
public boolean equals(Object o) {
// ...
}
}
What is this code here?
Observable<String> getCurrentLanguage() {
return getSystemLanguage()
.skip(1)
.first();
}
Observable<String> getCurrentLanguage() {
return getSystemLanguage()
// .skip(1)
.first();
}
Test Driven Development
Less Code Less Tests Peace of mind
Be playful Don’t be dogmatic
Find a test mentor
“Everyone knows that debugging is twice as
hard as writing a program in the first place.
So if you're as clever as you can be when
you write it, how will you ever debug it?”
Brian Kernighan
Thank you!
tpolansk

More Related Content

Viewers also liked

Las responsabilidades del ingeniero parte 3
Las responsabilidades del ingeniero parte 3 Las responsabilidades del ingeniero parte 3
Las responsabilidades del ingeniero parte 3 Danfer De la Cruz
 
Fendi - Puspitek Customer Interview
Fendi - Puspitek Customer InterviewFendi - Puspitek Customer Interview
Fendi - Puspitek Customer InterviewFendi Sinatra
 
Critical Thinking A Habit of Mind
Critical Thinking A Habit of MindCritical Thinking A Habit of Mind
Critical Thinking A Habit of MindNancy Wozniak
 
Designer_ Inst _Elect_ Liaqat Ali
Designer_ Inst _Elect_ Liaqat AliDesigner_ Inst _Elect_ Liaqat Ali
Designer_ Inst _Elect_ Liaqat AliLiaqat Ali
 
JESSICA_LI_REI
JESSICA_LI_REIJESSICA_LI_REI
JESSICA_LI_REIJessica Li
 
Улица Себастия
Улица СебастияУлица Себастия
Улица Себастияgexarvest
 
Я и моя семья
Я и моя семьяЯ и моя семья
Я и моя семьяgexarvest
 
10 gb ethernet
10 gb ethernet10 gb ethernet
10 gb ethernetronpoul
 
Волшебница осень
Волшебница осеньВолшебница осень
Волшебница осеньgexarvest
 

Viewers also liked (12)

Las responsabilidades del ingeniero parte 3
Las responsabilidades del ingeniero parte 3 Las responsabilidades del ingeniero parte 3
Las responsabilidades del ingeniero parte 3
 
Fendi - Puspitek Customer Interview
Fendi - Puspitek Customer InterviewFendi - Puspitek Customer Interview
Fendi - Puspitek Customer Interview
 
Critical Thinking A Habit of Mind
Critical Thinking A Habit of MindCritical Thinking A Habit of Mind
Critical Thinking A Habit of Mind
 
Designer_ Inst _Elect_ Liaqat Ali
Designer_ Inst _Elect_ Liaqat AliDesigner_ Inst _Elect_ Liaqat Ali
Designer_ Inst _Elect_ Liaqat Ali
 
JESSICA_LI_REI
JESSICA_LI_REIJESSICA_LI_REI
JESSICA_LI_REI
 
The BIG BOSS TURKEY
The BIG BOSS TURKEYThe BIG BOSS TURKEY
The BIG BOSS TURKEY
 
Улица Себастия
Улица СебастияУлица Себастия
Улица Себастия
 
Attairu CV (1)
Attairu CV (1)Attairu CV (1)
Attairu CV (1)
 
Я и моя семья
Я и моя семьяЯ и моя семья
Я и моя семья
 
10 gb ethernet
10 gb ethernet10 gb ethernet
10 gb ethernet
 
BSU-AQR-Case-Study
BSU-AQR-Case-StudyBSU-AQR-Case-Study
BSU-AQR-Case-Study
 
Волшебница осень
Волшебница осеньВолшебница осень
Волшебница осень
 

Similar to WHY USE UNIT TESTS

Mutation testing
Mutation testingMutation testing
Mutation testing기영 이
 
Mutation Testing: Start Hunting The Bugs
Mutation Testing: Start Hunting The BugsMutation Testing: Start Hunting The Bugs
Mutation Testing: Start Hunting The BugsAri Waller
 
Mutation testing Bucharest Tech Week
Mutation testing Bucharest Tech WeekMutation testing Bucharest Tech Week
Mutation testing Bucharest Tech WeekPaco van Beckhoven
 
Improve unit tests with Mutants!
Improve unit tests with Mutants!Improve unit tests with Mutants!
Improve unit tests with Mutants!Paco van Beckhoven
 
7 stages of unit testing
7 stages of unit testing7 stages of unit testing
7 stages of unit testingJorge Ortiz
 
Google test training
Google test trainingGoogle test training
Google test trainingThierry Gayet
 
Test Driven Development
Test Driven DevelopmentTest Driven Development
Test Driven Developmentguestc8093a6
 
Design principles - SOLID
Design principles - SOLIDDesign principles - SOLID
Design principles - SOLIDPranalee Rokde
 
First steps in testing analytics: Does test code quality matter?
First steps in testing analytics: Does test code quality matter?First steps in testing analytics: Does test code quality matter?
First steps in testing analytics: Does test code quality matter?Andy Zaidman
 
TDD reloaded - JUGTAA 24 Ottobre 2012
TDD reloaded - JUGTAA 24 Ottobre 2012TDD reloaded - JUGTAA 24 Ottobre 2012
TDD reloaded - JUGTAA 24 Ottobre 2012Pietro Di Bello
 
Tdd is not about testing (OOP)
Tdd is not about testing (OOP)Tdd is not about testing (OOP)
Tdd is not about testing (OOP)Gianluca Padovani
 
Getting Started with Test-Driven Development at Midwest PHP 2021
Getting Started with Test-Driven Development at Midwest PHP 2021Getting Started with Test-Driven Development at Midwest PHP 2021
Getting Started with Test-Driven Development at Midwest PHP 2021Scott Keck-Warren
 
Mutation Testing with PIT
Mutation Testing with PITMutation Testing with PIT
Mutation Testing with PITRafał Leszko
 
The real beginner's guide to android testing
The real beginner's guide to android testingThe real beginner's guide to android testing
The real beginner's guide to android testingEric (Trung Dung) Nguyen
 
STAMP Descartes Presentation
STAMP Descartes PresentationSTAMP Descartes Presentation
STAMP Descartes PresentationSTAMP Project
 
Software Testing
Software TestingSoftware Testing
Software TestingAdroitLogic
 
utPLSQL: Unit Testing for Oracle PL/SQL
utPLSQL: Unit Testing for Oracle PL/SQLutPLSQL: Unit Testing for Oracle PL/SQL
utPLSQL: Unit Testing for Oracle PL/SQLSteven Feuerstein
 

Similar to WHY USE UNIT TESTS (20)

Design for Testability
Design for TestabilityDesign for Testability
Design for Testability
 
Mutation testing
Mutation testingMutation testing
Mutation testing
 
Mutation Testing: Start Hunting The Bugs
Mutation Testing: Start Hunting The BugsMutation Testing: Start Hunting The Bugs
Mutation Testing: Start Hunting The Bugs
 
Mutation testing Bucharest Tech Week
Mutation testing Bucharest Tech WeekMutation testing Bucharest Tech Week
Mutation testing Bucharest Tech Week
 
Best practices unit testing
Best practices unit testing Best practices unit testing
Best practices unit testing
 
Improve unit tests with Mutants!
Improve unit tests with Mutants!Improve unit tests with Mutants!
Improve unit tests with Mutants!
 
7 stages of unit testing
7 stages of unit testing7 stages of unit testing
7 stages of unit testing
 
Google test training
Google test trainingGoogle test training
Google test training
 
Test Driven Development
Test Driven DevelopmentTest Driven Development
Test Driven Development
 
Design principles - SOLID
Design principles - SOLIDDesign principles - SOLID
Design principles - SOLID
 
First steps in testing analytics: Does test code quality matter?
First steps in testing analytics: Does test code quality matter?First steps in testing analytics: Does test code quality matter?
First steps in testing analytics: Does test code quality matter?
 
TDD reloaded - JUGTAA 24 Ottobre 2012
TDD reloaded - JUGTAA 24 Ottobre 2012TDD reloaded - JUGTAA 24 Ottobre 2012
TDD reloaded - JUGTAA 24 Ottobre 2012
 
Tdd is not about testing (OOP)
Tdd is not about testing (OOP)Tdd is not about testing (OOP)
Tdd is not about testing (OOP)
 
Mutation Testing
Mutation TestingMutation Testing
Mutation Testing
 
Getting Started with Test-Driven Development at Midwest PHP 2021
Getting Started with Test-Driven Development at Midwest PHP 2021Getting Started with Test-Driven Development at Midwest PHP 2021
Getting Started with Test-Driven Development at Midwest PHP 2021
 
Mutation Testing with PIT
Mutation Testing with PITMutation Testing with PIT
Mutation Testing with PIT
 
The real beginner's guide to android testing
The real beginner's guide to android testingThe real beginner's guide to android testing
The real beginner's guide to android testing
 
STAMP Descartes Presentation
STAMP Descartes PresentationSTAMP Descartes Presentation
STAMP Descartes Presentation
 
Software Testing
Software TestingSoftware Testing
Software Testing
 
utPLSQL: Unit Testing for Oracle PL/SQL
utPLSQL: Unit Testing for Oracle PL/SQLutPLSQL: Unit Testing for Oracle PL/SQL
utPLSQL: Unit Testing for Oracle PL/SQL
 

WHY USE UNIT TESTS

  • 2. “Too much time pressure with making visible changes. Customer doesn't appreciate tests enough.”
  • 3. “To make iterations as fast as possible I would not use tests for prototypes or early MVPs.”
  • 4. “Specs are too volatile, tests would just need to be updated constantly.”
  • 5. “Writing tests is hard, they might be difficult to understand.”
  • 6. “Nobody else in the project uses them. They weren't done or were broken when I got involved.”
  • 7. Time and budget “Too much time pressure with making visible changes”
  • 8. Instant changes Return on investment vs
  • 16. Architecture “Tests are hard and difficult to understand”
  • 18. What should unit tests look like?
  • 19. Fast
  • 21. Simple to understand @Test public void get_whenElementExists() { List<String> list = Collections.singletonList(DEFAULT); assertThat(get(list, 0)).isEqualTo(DEFAULT); } @Test public void get_whenIndexTooBig_returnNull() { List<String> list = Collections.singletonList(DEFAULT); assertThat(get(list, 1)).isNull(); } @Test public void get_whenIndexTooSmall_returnNull() { List<String> list = Collections.singletonList(DEFAULT); assertThat(get(list, -1)).isNull(); }
  • 24. @Test public void insertBuilder_withTable_withColumn_doesNotThrow() { new Builder().table(TABLE) .addColumn(COLUMN1) .build(); } @Test(expected = IllegalStateException.class) public void insertBuilder_withoutColumns_throwsException() { new Builder().table(TABLE) .build(); } Similar tests
  • 25. Test setup @Test public void test() { List<Language> list = Arrays.asList(GERMAN, ENGLISH); Mockito.when(mDataModel.getSupportedLanguages()) .thenReturn(list); Mockito.when(mDataModel.getGreetingByLanguageCode(LanguageCode.EN)) .thenReturn("Hi!"); // The rest of the test }
  • 26. Arrange builder class ArrangeBuilder { ArrangeBuilder withLanguages(Language... languages) { Mockito.when(mDataModel.getSupportedLanguages()) .thenReturn(Arrays.asList(languages)); return this; } ArrangeBuilder withGreetings(LanguageCode code, String greeting) { Mockito.when(mDataModel.getGreetingByLanguageCode(code)) .thenReturn(greeting); return this; } }
  • 27. @Test public void test() { List<Language> list = Arrays.asList(GERMAN, ENGLISH); Mockito.when(mDataModel.getSupportedLanguages()) .thenReturn(list); Mockito.when(mDataModel.getGreetingByLanguageCode(LanguageCode.EN)) .thenReturn("Hi!"); // The rest of the test } @Test public void test() { new ArrangeBuilder() .withLanguages(GERMAN, ENGLISH) .withGreetings(LanguageCode.EN, "Hi!"); // The rest of the test } Arrange builder
  • 30. Do I have enough tests?
  • 31. static boolean isEven(int number) { return number % 2 == 0; } static boolean isEven(int number) { return number % 2 == 0 ? true : false; } What’s the code coverage? @Test public void isTwoEven() { assertThat(isEven(2)) .isTrue(); } static boolean isEven(int number) { if ( number % 2 == 0 ) { return true; } else { return false; } }
  • 32. What’s the code coverage? Observable<Boolean> isEven(int number) { return Observable.just(number) .map(num -> num % 2 == 0); } @Test public void isTwoEven() { TestSubscriber<Boolean> ts = new TestSubscriber<>(); isEven(2).subscribe(ts); ts.assertValue(true); } @Test public void isTwoEven() { TestSubscriber<Boolean> ts = new TestSubscriber<>(); isEven(2).subscribe(ts); }
  • 33. Do I have too many tests?
  • 34. Do I have too much code?
  • 35. public class Translation { public final String mText; public Translation(String text) { mText = text; } public String text() { return mText; } } @AutoValue public abstract class Translation { public abstract String text(); public static Translation create(String text) { return new AutoValue_Translation(text); } } . public class Translation { private final String mText; public Translation(String text) { mText = text; } public String text() { return mText; } @Override public int hashCode() { return mText != null ? mText.hashCode() : 0; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Translation that = (Translation) o; return mText != null ? mText.equals(that.mText) : that.mText == null; } } . @Test public void valueEquality() { String value = "text"; Translation first = Translation.create(value); Translation second = Translation.create(value); assertThat(first).isEqualTo(second); } @AutoValue public abstract class Translation { public abstract String text(); public static Translation create(String text) { return new AutoValue_Translation(text); } @Override public int hashCode() { // ... } @Override public boolean equals(Object o) { // ... } }
  • 36. What is this code here? Observable<String> getCurrentLanguage() { return getSystemLanguage() .skip(1) .first(); } Observable<String> getCurrentLanguage() { return getSystemLanguage() // .skip(1) .first(); }
  • 37. Test Driven Development Less Code Less Tests Peace of mind
  • 38. Be playful Don’t be dogmatic Find a test mentor
  • 39.
  • 40. “Everyone knows that debugging is twice as hard as writing a program in the first place. So if you're as clever as you can be when you write it, how will you ever debug it?” Brian Kernighan

Editor's Notes

  1. Welcome everybody, My name is Tomasz Polanski and I’ve been a mobile software developer for the past 10 years. During this time I made plenty of mistakes, but also I’ve learned from them. That’s why I am excited to have this opportunity to share my knowledge with you about testing and why I think it's important. Don’t want to break it Surprising amount of bugs Sit with a person Feedback loop Focus on UT Shiny Why don’t write Whenever we join a project or inherit one form other team, the last thing you want to do is to break it. As we know, changing a single line of code can fix one bug, but at the same time, it can create a surprising amount of new ones. It would be nice to sit with a person that has done it, to tell you, what you can or cannot be doing. That’s why we need some sort of an instant feedback loop to let us know if we broke anything with our changes. That’s why tests were introduces. Automated testing is a really big subject to talk about, that’s why I will mainly focus on Unit Tests. When I will say tests, I will mostly mean Unit Tests, unless said otherwise. (Add new slide) Getting a shiny new project with a whole suite of tests, nice architecture and documentation, does not happens so often. That’s why I was interested why people not always write tests. I’ve surveyed other developers asking them in what cases they wouldn’t be creating tests for the project. Not surprisingly, the answers were similar. Here are the most frequent. And please rise your hand if you thought at some point the same.
  2. Deliver within time & budget Customer value is synonym of visual content Goosebumps when refactoring Refactoring does not change behavior Enjoy PO Refactoring part of process Hard refactoring without test Every team is pressured to deliver value to the customer within given time and budget. For the project stake holders, usually value is the synonym of visual content, therefor some product owners focus to deliver as much UI changes as possible. On the other hand, there are managers who get goosebumps when mentioning the word “refactoring”. That’s because refactoring by definition does not bring change to behavior of the product. Developers and PO, that we enjoy working with, know that refactoring is part of the process and without it, project would be unmaintainable in the future.
  3. Only verity behavior – no instant value Invest in future Being thankful for the test If you write tests to verify proper behavior of your code, you don’t get instant value. With tests, you invest in the future. Next time you change that code, you will be thankful that the test prevented you from making a mistake.
  4. Speed important factor Talk about distance Sprinter vs marathoner Same for project Speed of development is a really important factor. But when talking about speed we need to talk also about “distance”. We know that in running, a sprinter is faster then a marathoner and will win almost all 100m dashes. But if he or she would compete with a marathoner on 42km, then the marathoner would have the edge. The same goes with projects.
  5. Duration is crucial Short project – no tests? The longer- the more validation The duration of the project is crucial, if the project is small and will take really short amount of time, sometimes tests might be unnecessary. The longer the project takes, the more crucial is it’s constant validation.
  6. Prototypes and MVPs not in the same bucket Validate theory Learn Quality does not matter Crashes, pink rectangles Throwaway Sometimes MVPs - bad So when talking about prototypes and minimal viable products, I wouldn’t put them in the same basket. Prototypes should be used to validate a theory and learn from the outcome,  the quality of prototypes usually does not matter. You do not care if it crashes or instead of images you have pink rectangles. Prototype should be a throwaway code. Sometimes people are reusing that code in production because “it works”, but that’s entirely different story.
  7. Production ready Limited scope Quick customer value MVPs are production ready applications that have as limited scope as possible,  the reason behind it, is to deliver as quickly as possible a product to the customer, that he or she will find useful.
  8. Volatile and chaotic sector Industry where only constant is change Ways of handling chaos The more spec change -> the more code changes Tests are not a problem, they sre a solution Tests – coherent and predictable state The more changes – the more errors IT is one of the most volatile and chaotic sector . We are in an industry where the only constant is the change! That’s why we are always looking for ways to adjust to handle all this chaos. TODO: Saying that we shouldn’t write test because requirements changes so often is like saying … The more changes in the specs, the more changes in the code. Tests will keep your code in coherent and predictable state. Remember, the more code you change, the bigger chance to make an error.
  9. Test because writing software is hard The bigger -> the more complex -> the more things go wrong Window metaphore The reason why we test software is because writing software is hard! The bigger it is,  the more complex it is,  the more things could go wrong.   Window
  10. Two approaches Test verify only codes behavior Test used as specification and documentation Check behavior and tell dev hot to use them Documentation gets outdated, tests not Test are consumer of code Hard to write test = hard to use by devs More love for the code You can approach writing tests in two ways: - you can think that test should only verify code’s behavior or - think of tests as documentation and specification of your software - not only it will let you know when the behavior changed,  additionally it can tell other developers how they should use it It’s really useful approach, as documentation can get outdated if people forget to change it,  test on the other hand will fail if they won't be updated So keep in mind that tests are yet another consumers of your code,  the same as any other developer you work with.  If it’s hard to write a test for code,  most likely it will be hard for others to use it as well.   Difficulty in writing test might mean that the code could use some more love
  11. Messy code- urge to rewrite Takes months Behavior will be different It’s not refactoring Refactoring is also wrong behavior Missing tests = too coupled architecture Try something else Extract piece -> test it -> refactor Whenever we take over a messy code base,  there is an urge to rewrite everything from scratch.  This approach can take months. If there were no tests before,  it is highly possible that the product will behave differently. People sometimes call it refactoring, but there is no such a thing as refactoring without tests! Refactoring is a change of the code without changing the behavior - even if it was wrong! The reason for missing tests usually is that the architecture was not decoupled enough. Instead of dumping everything and starting anew try something different. You should try to extract the smallest part of the code that could be extracted, write tests for it – and then refactor.
  12. Fast or wont be run Avoid heavy frameworks Mock everything IO < 50ms They should be fast, otherwise people won’t even run them. Try to avoid frameworks that do magic behind scenes, but at the same time increase time for tests to run. Try mock everything related to IO, accessing disk or network will always take long time. For me, unit test should take less then 50ms to run.
  13. Random fails = frustration and doubt No it testing They should be reliable. If there are tests that randomly fail, try to find and fix them, otherwise they will bring plenty of frustration and doubt in your test suite. This is another reason why you should not use IO in your Unit Test, as there is too much random behavior to it.
  14. Simple at a glance 1 min of reading – too much They should be simple to understand with a single glance. If you need to read them for 1 minute to understand what they are doing, then something went wrong.
  15. Simple but long Cut them Use assertion helpers There are tests that look simple enough but still are doing too much stuff. (Animation) You can always cut them into smaller tests, use helper assertions or use plain equals from those objects, to check if your code is correct.
  16. 2011 Bill Wake Arrange Act Assert Don’t mix Separate To create simple test, in 2011 Bill Wake suggested triple A approach: Arrange Act Assert. Keep your test code confindent to those 3 blocks. Do not mix them together. If you see need for intwining Act and Assert, that could mean that you can do it in separate test.
  17. Similar test with one difference Easier to find issue Compare with the test above If you are writing more complex tests, make sure that there is only one difference between them. If one test is failing, it should be enough to compare it with the one above to know which part makes it to fail.
  18. Troublesome setup Simplify Sometimes you could have more complex setup of the test, for example like here with mockito. Try to simplify it.
  19. Declarative code is usually easier to read One thing that we tend to use is something that I call an Arrange Builder. If you are fan of more declarative code, you can put all the messy setup code into such a method
  20. Its reusable After that you can omit all the messy code and have clear, reusable test setup.
  21. How to start? How to end! Another thing is that tests should be easy to write. But when you start writing your test, thinking what variable you need and what should be order of acting, you can forget what you wanted to assert. That’s why you can start from the end!
  22. When asking this question, the phrase “code coverage” seems to obvious.
  23. Mention jacoco So how many tests should we write? A colleague of mine used to say to “write tests until you’re confident about your code”. Unfortunately I am not as smart as he is so I need to have another way to be confident about code I write. So can you guess the coverage for this test with Android Studio? 100%. But now let’s remove assertion completely. Guess shat is the coverage? 100%! As you can see that usually way of measuring how much code is tested has big gaps.
  24. We can possibly agree that too little tests is not a good thing. BUt is it ok to have too many tests? I do not mean now having a tests for a single piece of code. I mean accidentally writing a new tests, without knowing that this kind of test already exists. Unit tests are additional code base to maintain. Making sure that it is as big as needed, not bigger, is also important for entire code base maintainability.
  25. In the project we had a leftover model object. I wanted to cleaned it up because of multiple reasons: it was mutable, didn’t have any tests, didn’t override stuff like toString, equals, hashCode. Basically it was a mess. Now in project we create our immutable model classes with AutoValue, really usefull extension that during compile time generates all the boilerplate code that models should have. If anyone used kotlin, it’s similar to data class. After I was done with testing and writing the basic functionality, I wanted to add parcering. Now I will tell you what would have happened if I would have written the code and then the tests in the normal way: I would have copied the two methods and the Creator code to the autovalue abstract class. Next I would have written tests to check if the parceling works. And it would work. The last thing that I would do is give myself a pad on the back for the job well done. The issue is that I wouldn’t deserve that pat on the back. What accutally happened, is that I’ve added empty implementation for Parcalable. Next I’ve written the parceling tests, with expectation that the tests will fail, right? To my surprise, they’ve passed successfully. I did what any Android developer would do, synced gradle and cleaned cuple of times, still with the same result. In the end I;ve learned that AutoValue is so nice (and powerfull) that it also gererated all the code I needed. Thanks to it I didn’t need to write any more code and from 90 something lines of code I’ve came to 9 (counting empty lines)
  26. All those issues I’ve solved using Test Driven Development. In the beginning you might think that you slow down when using TDD, but after short time, writhing tests first will make you even faster. You will need to write less code, because you will be able to refactor without worrying about breaking things. You won’t need to think if you need more tests, because there is no code without tests. And not longer you will say: “The story is almost done, but I need to write tests” because you will have all the needed test even before you have the code!