Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Cooking with Spek

AppFoundry
September 22, 2016

Cooking with Spek

Presentation by Simon Vergauwen about Spek.
Spek is a BDD testing framework in Kotlin, written by Jetbrains. This talk also covers advanced testing with unMock, Mockito & PowerMock.

AppFoundry

September 22, 2016
Tweet

More Decks by AppFoundry

Other Decks in Technology

Transcript

  1. Cooking with Spek Spek Clean Testing Basic spek test Spek

    structure Iterative testing Technology Compatibility Kits (TCK)
  2. Coding Example Simple Method @file:JvmName("JsonUtil")
 package be.appfoundry.spekdemo.util
 
 import android.support.v4.util.ArrayMap


    import android.util.JsonWriter
 import java.io.StringWriter fun writeToJson(values: ArrayMap<String, String>): String {
 // Impl
 }
  3. Coding Example JUnit Test public class JsonUtilUnitTest {
 
 ArrayMap<String,String>

    arrayMap;
 
 @Before
 public void setUp() throws Exception {
 arrayMap = new ArrayMap<>();
 } 
 @After
 public void tearDown() throws Exception { }
 }
  4. Coding Example JUnit Test public class JsonUtilUnitTest {
 
 ArrayMap<String,String>

    arrayMap;
 
 @Before
 public void setUp() throws Exception {
 arrayMap = new ArrayMap<>();
 } 
 @Test
 public void testWriteSingleMapToJSON() {
 arrayMap.put("A","B");
 String json = JsonUtil.writeToJson(arrayMap);
 assertThat(json, containsString("\"A\":\"B\""));
 }
 
 @After
 public void tearDown() throws Exception { }
 }
  5. Coding Example Spek setup //setup kotlin testCompile "org.jetbrains.kotlin:kotlin-stdlib:1.0.3"
 testCompile “org.jetbrains.kotlin:kotlin-test:1.0.3”

    //setup spek
 testCompile "org.jetbrains.spek:spek-api:1.0.89"
 testCompile “org.jetbrains.spek:spek-junit-platform-engine:1.0.89" //setup unit platform runner
 testCompile "org.junit.platform:junit-platform-runner:1.0.0-M2"
  6. Coding Example Basic Spek test @RunWith(JUnitPlatform::class) class JsonWriterUnitTest : Spek({


    context("A json writer") {
 given("a single value map") {
 val singleValueMap = arrayMapOf(Pair("A", "B"))
 }
 }
 })
  7. Coding Example Basic Spek test @RunWith(JUnitPlatform::class)
 class JsonWriterUnitTest : Spek({


    context("A json writer") {
 given("a single value map") {
 val singleValueMap = arrayMapOf(Pair("A", "B"))
 
 it("should contain A:B") {
 val json = writeToJson(singleValueMap)
 assertThat(json, containsString("\"A\":\"B\""))
 }
 }
 }
 })
  8. Coding Example Simple Method @file:JvmName("JsonUtil")
 package be.appfoundry.spekdemo.util
 
 import android.support.v4.util.ArrayMap


    import android.util.JsonWriter
 import java.io.StringWriter fun writeToJson(values: ArrayMap<String, String>): String {
 // Impl
 }
  9. Coding Example Simple Method java.lang.RuntimeException: Method beginObject in android.util.JsonWriter not

    mocked. See http://g.co/androidstudio/not-mocked for details. at android.util.JsonWriter.beginObject(JsonWriter.java) at be.appfoundry.spekdemo.util.JsonUtil.writeToJson(JsonWriter.kt:12) at be.appfoundry.spekdemo.util.JsonWriterSpekTest $1$1$1$1.invoke(JsonWriterSpekTest.kt:21) at be.appfoundry.spekdemo.util.JsonWriterSpekTest $1$1$1$1.invoke(JsonWriterSpekTest.kt:14) at org.jetbrains.spek.engine.Scope$Test.execute(Scope.kt:110) at org.jetbrains.spek.engine.Scope$Test.execute(Scope.kt:83)
  10. Coding Example unMock apply plugin: 'de.mobilej.unmock'
 unMock {
 keep "android.webkit.URLUtil"


    keepStartingWith "android.util."
 } classpath “de.mobilej.unmock:UnMockPlugin:0.5.0” https://github.com/bjoernQ/unmock-plugin
  11. Coding Example Spek structure @RunWith(JUnitPlatform::class)
 class JsonWriterUnitTest : Spek({
 context("A

    json writer") {
 given("a single value map") {
 val singleValueMap = arrayMapOf(Pair("A", "B"))
 
 it("should contain A:B") {
 val json = writeToJson(singleValueMap)
 assertThat(json, containsString("\"A\":\"B\""))
 }
 }
 }
 })
  12. Coding Example Spek structure @RunWith(JUnitPlatform::class)
 class JsonWriterUnitTest : Spek({
 context("A

    json writer") {
 given("a single value map") {
 val singleValueMap = arrayMapOf(Pair("A", "B"))
 
 it("should contain A:B") {
 val json = writeToJson(singleValueMap)
 assertThat(json, containsString("\"A\":\"B\""))
 }
 }
 }
 })
  13. Coding Example Spek structure @RunWith(JUnitPlatform::class)
 class JsonWriterUnitTest : Spek({
 context("A

    json writer") {
 given("a single value map") {
 val singleValueMap = arrayMapOf(Pair("A", "B"))
 
 it("should contain A:B") {
 val json = writeToJson(singleValueMap)
 assertThat(json, containsString("\"A\":\"B\""))
 }
 }
 }
 }) abstract class Spek(val spec: Dsl.() -> Unit)
  14. Coding Example Spek structure @RunWith(JUnitPlatform::class)
 class JsonWriterUnitTest : Spek({
 context("A

    json writer") {
 given("a single value map") {
 val singleValueMap = arrayMapOf(Pair("A", "B"))
 
 it("should contain A:B") {
 val json = writeToJson(singleValueMap)
 assertThat(json, containsString("\"A\":\"B\""))
 }
 }
 }
 })
  15. Coding Example Spek structure @RunWith(JUnitPlatform::class)
 class JsonWriterUnitTest : Spek({
 context("A

    json writer") { beforeEach {//context beforeEach }
 given("a single value map") {
 val singleValueMap = arrayMapOf(Pair("A", "B"))
 
 it("should contain A:B") {
 val json = writeToJson(singleValueMap)
 assertThat(json, containsString("\"A\":\"B\""))
 }
 } afterEach {//context afterEach }
 }
 })
  16. Coding Example Spek structure @RunWith(JUnitPlatform::class)
 class JsonWriterUnitTest : Spek({
 context("A

    json writer") {
 given("a single value map") {
 val singleValueMap = arrayMapOf(Pair("A", "B"))
 
 it("should contain A:B") {
 val json = writeToJson(singleValueMap)
 assertThat(json, containsString("\"A\":\"B\""))
 }
 }
 }
 })
  17. Coding Example Spek structure @RunWith(JUnitPlatform::class)
 class JsonWriterUnitTest : Spek({
 context("A

    json writer") {
 given("a single value map") {
 val singleValueMap = arrayMapOf(Pair("A", "B"))
 beforeEach { //given beforeEach } 
 it("should contain A:B") {
 val json = writeToJson(singleValueMap)
 assertThat(json, containsString("\"A\":\"B\""))
 } afterEach { //given beforeEach }
 }
 }
 })
  18. Coding Example Spek structure @RunWith(JUnitPlatform::class)
 class JsonWriterUnitTest : Spek({
 context("A

    json writer") { beforeEach {//context beforeEach } 
 given("a single value map") {
 val singleValueMap = arrayMapOf(Pair("A", "B"))
 beforeEach { //given beforeEach } 
 it("should contain A:B") {
 val json = writeToJson(singleValueMap)
 assertThat(json, containsString("\"A\":\"B\""))
 } afterEach { //given beforeEach }
 } afterEach {//context afterEach }
 }
 })
  19. Coding Example Spek structure @RunWith(JUnitPlatform::class)
 class JsonWriterUnitTest : Spek({
 context("A

    json writer") {
 given("a single value map") {
 val singleValueMap = arrayMapOf(Pair("A", "B")) 
 then("should contain A:B") {
 val json = writeToJson(singleValueMap)
 assertThat(json, containsString("\"A\":\"B\""))
 }
 }
 }
 }) fun Dsl.then(description: String, body: () -> Unit) {
 test("then $description", body = body)
 }
  20. Coding Example Spek structure @RunWith(JUnitPlatform::class)
 class JsonWriterUnitTest : Spek({
 context("A

    json writer") {
 given("a single value map") {
 val singleValueMap = arrayMapOf(Pair("A", "B")) 
 xit("should contain A:B",reason = "pending version 2") {
 val json = writeToJson(singleValueMap)
 assertThat(json, containsString("\"A\":\"B\""))
 } }
 }
 })
  21. Coding Example JUnit example @RunWith(Parameterized.class)
 public class MainPresenterUnitTest {
 


    @Parameters
 public static String[] data() {
 return new String[]{"[email protected]", "[email protected]",
 “[email protected]", "@AppFoundryBE"};
 }
 
 public MainPresenterUnitTest(String input) {
 this.input = input;
 }
 }
  22. Coding Example JUnit example @RunWith(Parameterized.class)
 public class MainPresenterUnitTest {
 


    @Parameters
 public static String[] data() {
 return new String[]{"[email protected]", "[email protected]",
 “[email protected]", "@AppFoundryBE"};
 }
 
 public MainPresenterUnitTest(String input) {
 this.input = input;
 }
 
 @Before
 public void setUp() {
 mainView = mock(MainView.class);
 mainPresenter = new MainPresenter();
 mainPresenter.attachView(mainView);
 }
 
 @Test
 public void testIfItemIsShowAsEmail() {
 mainPresenter.processText(input);
 verify(mainView, times(1)).showItem(argThat(isA(MailItem.class)));
 }
 }
  23. Coding Example Iterative testing @RunWith(JUnitPlatform::class)
 class MainPresenterSpekTest : Spek({
 describe("The

    MainPresenter is handling the MainView") {
 var mainPresenter = MainPresenter()
 var mainView = mock<View>()
 
 beforeEach {
 mainPresenter = MainPresenter()
 mainView = mock<View>()
 mainPresenter.attachView(mainView)
 }
 
 on("processing a correctly formatted email adres") {
 listOf("[email protected]", "[email protected]",
 "[email protected]", "@AppFoundryBE").forEach { email ->
 it("should show $email") {
 mainPresenter.processText(email)
 verify(mainView, times(1)).showItem(argThat(isA(MailItem::class.java)))
 }
 }
 }
 }
 })
  24. Coding Example Iterative testing @RunWith(JUnitPlatform::class)
 class MainPresenterSpekTest : Spek({
 describe("The

    MainPresenter is handling the MainView") {
 var mainPresenter = MainPresenter()
 var mainView = mock<MainView>()
 
 beforeEach {
 mainPresenter = MainPresenter()
 mainView = mock<MainView>()
 mainPresenter.attachView(mainView)
 }
 
 on("processing a correctly formatted email adres") {
 listOf("[email protected]", "[email protected]",
 "[email protected]", "@AppFoundryBE").forEach { email -> 
 it("should show $email") {
 mainPresenter.processText(email)
 verify(mainView, times(1)).showItem(argThat(isA(MailItem::class.java)))
 }
 }
 }
 }
 })
  25. Coding Example Iterative testing @RunWith(JUnitPlatform::class)
 class MainPresenterSpekTest : Spek({
 describe("The

    MainPresenter is handling the MainView") {
 var mainPresenter = MainPresenter()
 var mainView = mock<View>()
 
 beforeEach {
 mainPresenter = MainPresenter()
 mainView = mock<View>()
 mainPresenter.attachView(mainView)
 }
 
 on("processing a correctly formatted email adres") {
 listOf("[email protected]", "[email protected]",
 "[email protected]", "@AppFoundryBE").forEach { email -> 
 it("should show $email") {
 mainPresenter.processText(email)
 verify(mainView, times(1)).showItem(argThat(isA(MailItem::class.java)))
 }
 }
 }
 }
 })
  26. Coding Example Iterative testing @RunWith(JUnitPlatform::class)
 class MainPresenterSpekTest : Spek({
 describe("The

    MainPresenter is handling the MainView") {
 var mainPresenter = MainPresenter()
 var mainView = mock<View>()
 
 beforeEach {
 mainPresenter = MainPresenter()
 mainView = mock<View>()
 mainPresenter.attachView(mainView)
 }
 
 on("processing a correctly formatted email adres") {
 listOf("[email protected]", "[email protected]",
 "[email protected]", "@AppFoundryBE").forEach { email -> 
 it("should show $email") {
 mainPresenter.processText(email)
 verify(mainView, times(1)).showItem(argThat(isA(MailItem::class.java)))
 }
 }
 }
 }
 })
  27. Coding Example TCK abstract class ItemTCK(val item: Item) : Spek({


    //spek test
 })
 
 class URLItemTCKTest : ItemTCK(URLItem("www.appfoundry.be"))
 
 class TwitterItemTCKTest : ItemTCK(TwitterItem("@AppFoundryBE"))
 
 class MailItemTCKTest : ItemTCK(MailItem("[email protected]"))
 
 class PhoneItemTCKTest : ItemTCK(PhoneItem("003238719966"))
  28. Coding Example TCK abstract class ItemTCK(val factory: () -> Item)

    : Spek({
 val item = factory() //spek test
 }) class URLItemTCKTest : ItemTCK({ URLItem("www.appfoundry.be") })
 
 class TwitterItemTCKTest : ItemTCK({ TwitterItem("@AppFoundryBE") })
 
 class MailItemTCKTest : ItemTCK({ MailItem("[email protected]") })
 
 class PhoneItemTCKTest : ItemTCK({ PhoneItem("003238719966") })
  29. Coding Example TCK @RunWith(PowerMockRunner::class)
 @PowerMockRunnerDelegate(JUnitPlatform::class)
 @PrepareForTest(ContextCompat::class)
 abstract class ItemTCK(val factory:

    () -> Item) : Spek({
 val item = factory() 
 describe("handling an item object") {
 val context = mock<Context>()
 val drawable = mock<Drawable>()
 beforeEach {
 PowerMock.mockStatic(ContextCompat::class.java)
 whenever(ContextCompat.getDrawable(any<Context>(), any<Int>()))
 .thenReturn(drawable)
 }
 
 }
 })
  30. Coding Example TCK @RunWith(PowerMockRunner::class)
 @PowerMockRunnerDelegate(JUnitPlatform::class)
 @PrepareForTest(ContextCompat::class)
 abstract class ItemTCK(val factory:

    () -> Item) : Spek({
 val item = factory() 
 describe("handling an item object") {
 val context = mock<Context>()
 val drawable = mock<Drawable>()
 beforeEach {
 PowerMock.mockStatic(ContextCompat::class.java)
 whenever(ContextCompat.getDrawable(any<Context>(), any<Int>()))
 .thenReturn(drawable)
 }
 
 it("should never have a null name") {
 assertThat(item.name, notNullValue())
 }
 it("should always have a color id") {
 assertThat(item.itemColorId, isA(Int::class.java))
 }
 it("should always return a drawable") {
 assertThat(item.getIcon(context), equalTo(drawable))
 }
 }
 })
  31. Coding Example Simple Rx function java.lang.ExceptionInInitializerError at rx.android.schedulers.AndroidSchedulers.mainThread(AndroidSchedulers.java:39) at be.appfoundry.spekdemo.util.RxMethodKt.doSomeRxing(RxMethod.kt:8)

    at be.appfoundry.spekdemo.util.RxTest$1$1$2.invoke(RxTest.kt:22) at be.appfoundry.spekdemo.util.RxTest$1$1$2.invoke(RxTest.kt:16) at org.jetbrains.spek.engine.Scope$Test.execute(Scope.kt:110) at org.jetbrains.spek.engine.Scope$Test.execute(Scope.kt:83) ...
 
 Caused by: java.lang.RuntimeException: Method getMainLooper in android.os.Looper not mocked. See http://g.co/androidstudio/not-mocked for details. at android.os.Looper.getMainLooper(Looper.java) at rx.android.schedulers.AndroidSchedulers $MainThreadSchedulerHolder.<clinit>(AndroidSchedulers.java:31) ... 32 more
  32. Coding Example JUnit rule for Rx public class RxJavaResetRule implements

    TestRule {
 @Override
 public Statement apply(final Statement base, final Description description) {
 
 } }
  33. Coding Example JUnit rule for Rx public class RxJavaResetRule implements

    TestRule {
 @Override
 public Statement apply(final Statement base, final Description description) {
 return new Statement() {
 @Override
 public void evaluate() throws Throwable {
 //@Before
 
 base.evaluate();
 
 //@After
 } 
 };
 } }
  34. Coding Example JUnit rule for Rx public class RxJavaResetRule implements

    TestRule {
 @Override
 public Statement apply(final Statement base, final Description description) {
 return new Statement() {
 @Override
 public void evaluate() throws Throwable {
 //@Before
 RxJavaPlugins.getInstance().reset();
 RxJavaPlugins.getInstance().registerSchedulersHook(rxJavaHook);
 
 RxAndroidPlugins.getInstance().reset();
 RxAndroidPlugins.getInstance().registerSchedulersHook(rxAndroidHook);
 
 base.evaluate();
 
 //@After
 RxJavaPlugins.getInstance().reset();
 RxAndroidPlugins.getInstance().reset();
 } 
 };
 } //rxJavaHook & rxAndroidHook def }
  35. Coding Example JUnit rule for Rx public class RxUnitTest {


    @Rule
 public RxJavaResetRule rxJavaResetRule = new RxJavaResetRule();
 
 TestSubscriber<Long> testSubscriber;
 
 @Before
 public void setUp() {
 testSubscriber = new TestSubscriber<>();
 }
 }
  36. Coding Example JUnit rule for Rx public class RxUnitTest {


    @Rule
 public RxJavaResetRule rxJavaResetRule = new RxJavaResetRule();
 
 TestSubscriber<Long> testSubscriber;
 
 @Before
 public void setUp() {
 testSubscriber = new TestSubscriber<>();
 }
 
 @Test
 public void testRx() {
 RxMethodKt.doSomeRxing().subscribe(testSubscriber);
 
 assertThat(testSubscriber,
 allOf(onNextEvents(hasSize(1)), onNextEvents(hasItem(1L)),
 hasNoErrors(),
 isCompleted()));
 }
 }
  37. Coding Example Junit rule in Spek @RunWith(JUnitPlatform::class)
 class RxTest :

    Spek({
 on("testing something observed by an android schedulers") {
 var testSubscriber = TestSubscriber<Long>()
 beforeEach { testSubscriber = TestSubscriber<Long>() } 
 }
 })
  38. Coding Example Junit rule in Spek @RunWith(JUnitPlatform::class)
 class RxTest :

    Spek({
 on("testing something observed by an android schedulers") {
 var testSubscriber = TestSubscriber<Long>()
 beforeEach { testSubscriber = TestSubscriber<Long>() }
 
 it("should be easily tested in unit test") {
 doSomeRxing().subscribe(testSubscriber) 
 assertThat(testSubscriber,
 allOf(hasNoErrors(),
 onNextEvents(hasSize<Any>(1)),
 onNextEvents(hasItem(1L)),
 isCompleted()))
 }
 }
 })
  39. Coding Example Simple Rx function inline fun Dsl.rxGroup(description: String, pending:

    Pending = Pending.No,
 crossinline body: Dsl.() -> Unit) {
 
 group(description, pending) {
 }
 }
  40. Coding Example Simple Rx function inline fun Dsl.rxGroup(description: String, pending:

    Pending = Pending.No,
 crossinline body: Dsl.() -> Unit) {
 
 group(description, pending) {
 beforeEach {
 RxJavaPlugins.getInstance().reset()
 RxJavaPlugins.getInstance().registerSchedulersHook(rxJavaHook)
 
 RxAndroidPlugins.getInstance().reset()
 RxAndroidPlugins.getInstance().registerSchedulersHook(rxAndroidHook)
 }
 
 body()
 
 afterEach {
 RxJavaPlugins.getInstance().reset()
 
 RxAndroidPlugins.getInstance().reset()
 }
 }
 }
  41. Coding Example Simple Rx function inline fun Dsl.rxGroup(description: String, pending:

    Pending = Pending.No,
 crossinline body: Dsl.() -> Unit) {
 
 group(description, pending) {
 beforeEach {
 RxJavaPlugins.getInstance().reset()
 RxJavaPlugins.getInstance().registerSchedulersHook(rxJavaHook)
 
 RxAndroidPlugins.getInstance().reset()
 RxAndroidPlugins.getInstance().registerSchedulersHook(rxAndroidHook)
 }
 
 body()
 
 afterEach {
 RxJavaPlugins.getInstance().reset()
 
 RxAndroidPlugins.getInstance().reset()
 }
 }
 } inline fun Dsl.onRx(description: String, crossinline body: Dsl.() -> Unit) =
 rxGroup("on $description", body = body)
  42. Coding Example Simple Rx function @RunWith(JUnitPlatform::class)
 class RxTest : Spek({


    on("when testing something observed by an android schedulers") {
 var testSubscriber = TestSubscriber<Long>()
 beforeEach { testSubscriber = TestSubscriber<Long>() }
 
 it("should be easily tested in unit test") {
 doSomeRxing().subscribe(testSubscriber) 
 assertThat(testSubscriber,
 allOf(hasNoErrors(),
 onNextEvents(hasSize<Any>(1)),
 onNextEvents(hasItem(1L)),
 isCompleted()))
 }
 }
 })
  43. Coding Example Simple Rx function @RunWith(JUnitPlatform::class)
 class RxTest : Spek({


    onRx("when testing something observed by an android schedulers") {
 var testSubscriber = TestSubscriber<Long>()
 beforeEach { testSubscriber = TestSubscriber<Long>() }
 
 it("should be easily tested in unit test") {
 doSomeRxing().subscribe(testSubscriber) 
 assertThat(testSubscriber,
 allOf(hasNoErrors(),
 onNextEvents(hasSize<Any>(1)),
 onNextEvents(hasItem(1L)),
 isCompleted()))
 }
 }
 })