I’m going to tell you a real story how we saved ourselves tons of time. The power of Kotlin’s refactoring is astounding. @Deprecated Don’t think it is the same as Java’s . It is much more powerful. It allows for multi-step automated replacement. @Deprecated So, let me tell you about it. We were migrating our code base from Java to Kotlin. When somebody needed to touch an existing Java file, we would auto-convert it to Kotlin. And only then introduce change. Otherwise, all new code was written in Kotlin. We were using library in our unit tests. And as you might know, mockito heavily relies on method. mockito Mockito.when is a reserved keyword in Kotlin. So we had to fence it with backticks. when To be honest, it looked quite ugly, and was awkward to type: class AccountTest { private val statementReporter = mock(AccountStatementReporter::class.java) private val account = Account(statementReporter) @Test fun `testing with Mockito when`() { `when`(statementReporter.canPrintItem()) .thenReturn(true) account.generateStatement() verify(statementReporter).printItem("-5,00\t73,91") } } At the time, we weren’t aware of the , so we have built our own function to mitigate the keyword problem: mockito-kotlin whenever fun <T> whenever(x: T): OngoingStub<T> { return `when`(x)} It is an alias for . Mockito.when And it can be typed quickly, and IntelliJ helps with autocomplete. Which is nice: @Test fun `testing with handcrafted whenever`() { whenever(statementReporter.canPrintItem()) .thenReturn(true) account.generateStatement() verify(statementReporter).printItem("-5,00\t73,91") } Over the course of half a year, we had this -based code everywhere. whenever Thousands of occurrences. @Test fun `testing with handcrafted whenever – false case`() { whenever(statementReporter.canPrintItem()) .thenReturn(false) account.generateStatement() verify(statementReporter).canPrintItem() verifyNoMoreInteractions(statementReporter) } At that point, somebody has discovered API. It has allowed us to use slightly different words for , , , and others. BDDMockito when thenReturn thenThrow Most importantly, it was part of the official library! mockito By the way, is usually used when testing in Java and Kotlin. mockito Curious about testing in Kotlin? Or Kotlin in general? I suggest you . You will be minutes away from your first full-fledged command-line application in Kotlin. download my free Ultimate Tutorial: Getting Started With Kotlin The tutorial is an 80-page book and is entirely hands-on. You can follow along with it while learning about various Kotlin and IntelliJ features. And lots of other things. Anyways. Here is an example of syntax for you: BDDMockito @Test fun `testing with handcrafted whenever`() { given(statementReporter.canPrintItem()) .willReturn(true) account.generateStatement() verify(statementReporter).printItem("-5,00\t73,91") } Of course, we wanted to switch from hand-crafted function to the official API! By the way, is using slightly different naming. But the mocking structure is same: BDDMockito // given vs whengiven(statementReporter.canPrintItem()) // willReturn vs thenReturn .willReturn(true) As you can see, instead of it allows us to use , and all the methods become . when given then* will* At that point, we decided to switch from to . We didn’t want to change thousands of occurrences in one go, as it will take a lot of time. whenever given And we just might have changed some things that shouldn’t have been changed if we were to do the search & replace. So, we decided to put a simple annotation on the function. That would make all the usages appear as deprecated (crossed out) in IntelliJ. New usages are unlikely to be introduced, as well. @Deprecated whenever As my pair was typing it out, I’ve noticed that IntelliJ was showing something interesting in the parameter list tooltip: It got me curious about this parameter. If I understood it correctly, this would allow some automated replacement. replaceWith We fiddled a bit with it. And it seemed like you can do such replacement. Here is the code: @Deprecated( "use BDDMockito.given", replaceWith = ReplaceWith( "given(x)", "org.mockito.BDDMockito.Companion.given"))fun <T> whenever(x: T): OngoingStub<T> { return `when`(x)} Now we tried to go to the usage of , place our cursor on the deprecated call, and press ALT + ENTER (the magic hotkey of IntelliJ). whenever whenever What happened is amazing: You can indeed do the automated replacement. And there is even an option to replace it in the WHOLE PROJECT! Astounding! But first, we decided to double-check how it will work just for that one occurrence. That was the right decision: It resulted in a compile error as doesn’t have method defined on it. It should be . BDDOngoingStub<T> thenReturn willReturn And now it got us thinking. What if we could define that method using “extension methods” feature of Kotlin? That would make things compile. Sure. But then we still didn’t get rid of the custom code yet… “So what if we deprecate that extension method too?!” — I asked. “And then we can add !” – my pair replied. replaceWith In rejoice, we started doing it: fun <T> BDDOngoingStub<T>.thenReturn(x: T) { willReturn(x)} That allowed us to fix the problem by auto-importing extension: thenReturn And now, we were about to deprecate it with the same kind of annotation: @Deprecated( "use willReturn", replaceWith = ReplaceWith( "willReturn(x)"))fun <T> BDDOngoingStub<T>.thenReturn(x: T) { willReturn(x)} Now we were able to replace these method calls with : thenReturn willReturn We could have run that replacement for the whole project, as well. Neat. We thought we were ready to do the “WHOLE PROJECT” refactoring: That still forced us to do “ALT+ENTER” auto-importing in about 40 files. But that, to be honest, was a quick one. There is a shortcut to jump to the next compile error: CMD+ALT+DOWN. So the fix for that little problem was to press one shortcut and another right after. Over and over and over again. It took us a minute to do that. We did the same “WHOLE PROJECT” replacement for too: thenReturn That worked without any problems: @Test fun `testing with handcrafted whenever`() { given(statementReporter.canPrintItem()) .willReturn(true) account.generateStatement() verify(statementReporter).printItem("-5,00\t73,91") } @Test fun `testing with handcrafted whenever – false case`() { given(statementReporter.canPrintItem()) .willReturn(false) account.generateStatement() verify(statementReporter).canPrintItem() verifyNoMoreInteractions(statementReporter) } Finally, we double-checked that there are no occurrences of , , and . whenever thenReturn thenThrow There wasn’t. So we safely removed our file. testutils/whenever.kt As you can guess, some wit goes into these definitions. But once in place – saves you a lot of time and relieves you of a lot of pain. @Deprecated I genuinely thank you for reading this piece. It was quite a ride for me. If you liked what you just read, I would appreciate some Medium claps! Social media shares are warmly welcome, as well. Same goes for the feedback! If you are just starting in Kotlin, you will . make me happy by downloading this free ultimate tutorial about getting started with Kotlin Thank you! More exciting reading _I hear what you are saying. There is that buzz around Android actively adopting Kotlin as a primary programming…_hackernoon.com How Kotlin Calamity Devours Your Java Apps Like Lightning? _Developers often complain about technical debt and want to get some time to fix it. Be it a significant refactoring, or…_hackernoon.com For CTO: When is the time to pay technical debt? _Let me guess…_hackernoon.com How to Find The Time to Learn a New Skill When You Are Working Full-Time?
Share Your Thoughts