1## Testing 2 3### Do not rely on mocks 4 5All APIs created in Jetpack **must have a testing story**: how developers should 6write tests for their code that relies on a library, this story should not be 7"use Mockito to mock class `Foo`". Your goal as an API owner is to **create 8better alternatives** to mocking. 9 10#### Why can't I suggest mocks as testing strategy? 11 12Frequently, mocks don't follow guarantees outlined in the API they mock. That 13leads to: 14 15* Significant difference in the behavior that diminishes test value. 16* Brittle tests, that make hard to evolve both apps and libraries, because new 17 code may start to rely on the guarantees broken in a mock. Let's take a look 18 at a simplified example. So, let's say you mocked a bundle and getString in 19 it: 20 21 ```java 22 Bundle mock = mock(Bundle.class); 23 when(mock.getString("key")).thenReturn("result"); 24 ``` 25 26 But you don't mock it to simply call `getString()` in your test. A goal is 27 not to test a mock, the goal is always to test your app code, so your app 28 code always interacts with a mock in some way: 29 30 ```java 31 Bundle bundle = mock(Bundle.class); 32 when(mock.getString("key")).thenReturn("result"); 33 mycomponent.consume(bundle) 34 ``` 35 36 Originally the test worked fine, but over time `component.consume` is 37 evolving, and, for example, it may start to call `containsKey` on the given 38 bundle. But our test passes a mock that don't expect such call and, boom, 39 test is broken. However, component code is completely valid and has nothing 40 to do with the broken test. We observed a lot of issues like that during 41 updates of Android SDK and Jetpack libraries to newer versions internally at 42 google. Suggesting to mock our own components is shooting ourselves in the 43 foot, it will make adoption of newer version of libraries even slower. 44 45* Messy tests. It always starts with simple mock with one method, but then 46 this mock grows with the project, and as a result test code has sub-optimal 47 half-baked class implementation of on top of the mock. 48 49#### But it's okay to mock interfaces, right? 50 51It depends. There are interfaces that don't imply any behavior guarantees and 52they are ok to be mocked. However, **not all** interfaces are like that: for 53example, `Map` is an interface but it has a lot of contracts required from 54correct implementation. Examples of interfaces that are ok to mock are callback 55interfaces in general, for example: `View.OnClickListener`, `Runnable`. 56 57#### What about spying? 58 59Spying on these classes is banned as well - Mockito spies permit stubbing of 60methods just like mocks do, and interaction verification is brittle and 61unnecessary for these classes. Rather than verifying an interaction with a 62class, developers should observe the result of an interaction - the effect of a 63task submitted to an `Executor`, or the presence of a fragment added to your 64layout. If an API in your library misses a way to have such checks, you should 65add methods to do that. 66 67#### Avoid Mockito in your own tests 68 69One of the things that would help you to identify if your library is testable 70without Mockito is not using Mockito yourself. Yes, historically we heavily 71relied on Mockito ourselves and old tests are not rewritten, but new tests 72shouldn't follow up that and should take as an example good citizens, for 73example, `-ktx` modules. These modules don't rely on Mockito and have concise 74expressive tests. 75 76One of the popular and legit patterns for Mockito usage were tests that verify 77that a simple callback-like interface receives correct parameters. 78 79```java 80class MyApi { 81 interface Callback { 82 void onFoo(Value value); 83 } 84 void foo() { … } 85 void registerFooCallback(Callback callback) {...} 86} 87``` 88 89In API like the one above, in Java 7 tests for value received in `Callback` 90tended to become very wordy without Mockito. But now in your tests you can use 91Kotlin and test will be as short as with Mockito: 92 93```kotlin 94fun test() { 95 var receivedValue = null 96 myApi.registerCallback { value -> receivedValue = value } 97 myApi.foo() 98 // verify receivedValue 99} 100``` 101 102#### Don't compromise in API to enable Mockito 103 104Mockito on Android 105[had an issue](https://github.com/Mockito/Mockito/issues/1173) with mocking 106final classes. Moreover, internally at Google this feature is disabled even for 107non-Android code. So you may hear complaints that some of your classes are not 108mockable, however **it is not a reason for open up a class for extension**. What 109you should instead is verify that is possible to write the same test without 110mocking, if not, again you should **provide better alternative in your API**. 111 112#### How do I approach testing story for my API? 113 114The best way is to step into developer's shoes and write a sample app that is a 115showcase for your API, then go to the next step - test that code also. If you 116are able to implement tests for your demo app, then users of your API will also 117be able to implement tests for functionalities where your API is also used. 118