Skip to content

Commit

Permalink
Adding tests (#64)
Browse files Browse the repository at this point in the history
* Kotlin Migration - Adapter and DI (#50)

* Adapter

* DI

* Converting object to class

* Fix pair

* Migrate BasePresenter

* Migrate LceView and add copyright to BasePresenter

* Migrate LeView

* Migrate BasePresenterTest

* Add deprecated to runIfViewAttached, replace apply for run in tests, clean code

* Migration of permissionsManager

* Migration of permissionListener

* Fix redundant private set

* Refactor to clean code

* More refactor

* Kotlin migration utils (#52)

* Keyboard

* Logger

* Shared preferences

* Migration (#53)

* WolmoActivityHandler converted to kotlin (#51)

* WolmoActivityHandler converted to kotlin

* WolmoActivityHandler converted to kotlin

* WolmoActivityHandler converted to kotlin

* Kotlin migration fragments (#56)

* FRagments migrated

* Restoring GetImage.java

* Restoring java getimage test

* To spaces

* Indentation

* Reformat

* Code reformats

* fixing tests

* Reverting get image fragment

* changing imports

* Last migration (#58)

* FRagments migrated

* Restoring GetImage.java

* Restoring java getimage test

* To spaces

* Indentation

* Reformat

* Code reformats

* fixing tests

* Last migration

* Kotlin migration fixes - update versions (#59)

* Fixing overriding base presenter

* Presenter as val

* Fix tests

* Get presnter instead of require

* Fixing wolmo fragment inject

* DefaultModule as class

* Shared preferences string nullable

* Android core as api

* Reverting modules

* Updating version

* Updating versions

* Fixing tests

* Using implmentation

* API insteda of implementation revert

* Rollback handler

* Also adding some minor changes

* Another minor change

* Updating comments and using requireArgument

* Handle arguments nullable on fragment

* Fixing url

* Adding coroutine base presenter

* Coroutines and more

* updating get image fragment

* Fixing doc

* Updating get image fragment

* Rollback handler and minor changes (#61)

* Rollback handler

* Also adding some minor changes

* Another minor change

* Updating comments and using requireArgument

* Handle arguments nullable on fragment

* Fixing url

* Removing wrong comment

* Updating get image

* Moving all get image stuff to a helper

* Fixing issues

* Some fixes

* Removing wrong test

* Serializable

* Importing

* Fixing

* Reverting image provider

* Provider change

* More fixes

* Removing wrong arguments

* More navigation utils

* Updating kapt

* Removing getimagekt

* Reverting get image fragment

* Reverting get image fragment test

* Reverting spaces

* More reverts

* More reverts

* Reverting tests

* More test reverts

* Minor fixes

* More comments

* Removing log

* Single lines

* Removing imports

* Updating gradle

* More tests

* Features readme

* Reformat

* View extensions readme

* Adding tests

* Typo

* Removing wrong startactivity

Co-authored-by: igsosa92 <43349271+igsosa92@users.noreply.github.com>
Co-authored-by: patofernandez <49655621+patofernandez@users.noreply.github.com>
  • Loading branch information
3 people authored Jan 8, 2020
1 parent 1b8d820 commit c41ea52
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 21 deletions.
8 changes: 8 additions & 0 deletions FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,11 @@ Base implementation of a `DaggerFragment` that is MVP-ready (you can access the

It also provides this extra feature:
- `requireArgument(key: String): T`: get argument by the given [key] and returns it as a non-null [T].

# Wolmo testing features

### WolmoPresenterTest
A base that setups the environment for a Wolmo's [BasePresenter] test. It also provides a prepared environment for annotated mocks.

### CoroutineTestRule
A Junit Test Rule that allows to use Coroutines main dispatcher on a test. If [runOnAllTests] is false then all tests will have this configuration, otherwise just those that have [CoroutineTest] annotation.
2 changes: 1 addition & 1 deletion core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ dependencies {

// Coroutines
api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version"

// Test
testImplementation "junit:junit:$junit_version"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package ar.com.wolox.wolmo.core.tests

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.setMain
import org.junit.rules.TestWatcher
import org.junit.runner.Description
import java.util.concurrent.Executors

/**
* If a test method is annotated with this, then the [CoroutineTestRule] will be executed.
* Use it when [CoroutineTestRule.runOnAllTests] is false.
*/
annotation class CoroutineTest

/**
* A Junit Test Rule that allows to use Coroutines main dispatcher on a test.
* If [runOnAllTests] is false then all tests will have this configuration,
* otherwise just those that have [CoroutineTest] annotation.
*/
@ExperimentalCoroutinesApi
class CoroutineTestRule(private val runOnAllTests: Boolean = false) : TestWatcher() {

private val mainThreadSurrogate = Executors.newSingleThreadExecutor().asCoroutineDispatcher()

private fun isCoroutineTest(description: Description?): Boolean {
return description?.annotations?.filterIsInstance<CoroutineTest>()?.isNotEmpty() == true
}

private fun shouldRunRule(description: Description?): Boolean {
return runOnAllTests || isCoroutineTest(description)
}

override fun starting(description: Description?) {
if (shouldRunRule(description)) {
Dispatchers.setMain(mainThreadSurrogate)
}
}

override fun finished(description: Description?) {
if (shouldRunRule(description)) {
Dispatchers.resetMain()
mainThreadSurrogate.close()
}
}
}
Original file line number Diff line number Diff line change
@@ -1,47 +1,41 @@
package ar.com.wolox.wolmo.core.tests

import ar.com.wolox.wolmo.core.presenter.BasePresenter
import org.junit.After
import org.junit.Before
import org.mockito.Mockito
import org.mockito.Mockito.mock
import org.mockito.MockitoAnnotations
import java.lang.reflect.ParameterizedType

/**
* A base that setups the environment for a Wolmo's [BasePresenter] test.
* It also provides a prepared environment for annotated mocks.
*/
abstract class WolmoPresenterTest<V : Any, P : BasePresenter<V>> {

/**
* The presenter to be tested.
*/
/** The presenter to be tested */
protected lateinit var presenter: P

/**
* The mocked view that the presenter will use.
*/
lateinit var view: V
/** The mocked view attached to the presenter. */
protected lateinit var view: V

@Suppress("UNCHECKED_CAST")
private fun getViewClass(): Class<V> {
return (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class<V>
}

/**
* Setup the environment.
*/
/** Setup the environment. */
@Before
fun setupWolmoPresenterTest() {
MockitoAnnotations.initMocks(this)
presenter = getPresenterInstance()
view = Mockito.mock(getViewClass())
presenter.attachView(view)
view = mock(getViewClass()).also { presenter.attachView(it) }
}

/**
* This method provides the presenter instance that will be tested.
* If the presenter should be spied, it's possible to return the presenter spied with [Mockito.spy].
*
* @return the [BasePresenter] instance.
*/
abstract fun getPresenterInstance(): P
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,17 +81,14 @@ fun Context.makeCall(phone: String) {
}

/**
* Sends an intent to start an [Activity] for the provided [clazz] from a [context]
* Sends an intent to start an [Activity] for the provided [clazz] from a [Context]
* with a variable number of instances of [intentExtras] that will be sent as extras.
*/
@SafeVarargs
fun Context.jumpTo(
clazz: Class<*>,
vararg intentExtras: IntentExtra
) = jumpTo(clazz, null, *intentExtras)
fun Context.jumpTo(clazz: Class<*>, vararg intentExtras: IntentExtra) = jumpTo(clazz, null, *intentExtras)

/**
* Sends an intent to start an [Activity] for the provided [clazz] from a [context]
* Sends an intent to start an [Activity] for the provided [clazz] from a [Context]
* with a variable number of instances of [intentExtras] that will be sent as extras.
* It accepts a [transition] that defines the animation behaviour.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package ar.com.wolox.wolmo.core.tests

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.runBlocking
import org.junit.Rule
import org.junit.Test

@ExperimentalCoroutinesApi
class CoroutineTestRuleTest {

@get:Rule
val coroutineTestRule = CoroutineTestRule(runOnAllTests = true)

@Test(expected = Test.None::class /* no exception expected */)
fun `given a rule with run on all tests true when run coroutine on main then there's no exception thrown`() {
runBlocking(Dispatchers.Main) {}
}
}

@ExperimentalCoroutinesApi
class CoroutineTestRuleTest2 {

@get:Rule
val coroutineTestRule = CoroutineTestRule(runOnAllTests = false)

@Test(expected = IllegalStateException::class)
fun `given a rule with run on all tests false when run coroutine on main then a IllegalStateException is thrown`() {
runBlocking(Dispatchers.Main) {}
}

@Test(expected = Test.None::class /* no exception expected */)
@CoroutineTest
fun `given a rule with run on all tests false and annotated with CoroutineScope when run coroutine on main then there's no exception thrown`() {
runBlocking(Dispatchers.Main) {}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package ar.com.wolox.wolmo.core.tests

import android.graphics.Rect
import ar.com.wolox.wolmo.core.presenter.BasePresenter
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.`is`
import org.hamcrest.Matchers.notNullValue
import org.junit.Test
import org.mockito.Mock
import org.mockito.Mockito.times
import org.mockito.Mockito.verify

class WolmoPresenterTestTest : WolmoPresenterTest<WolmoPresenterTestTest.TestView, WolmoPresenterTestTest.TestPresenter>() {

@Mock
lateinit var rectMocked: Rect

override fun getPresenterInstance() = TestPresenter()

private fun <T> tryToGet(getter: () -> T): T? = try {
getter()
} catch (ignored: Exception) {
null
}

@Test
fun `given a test when getting instances then those are not null`() {

val presenter = tryToGet { presenter }
val view = tryToGet { view }

assertThat(presenter, `is`(notNullValue()))
assertThat(view, `is`(notNullValue()))
}

@Test
fun `given an annotated mock when using it then it's not null`() {

val rectMocked = tryToGet { rectMocked }

assertThat(rectMocked, `is`(notNullValue()))
}

@Test
fun `given a presenter and a view when getting presenter get a call view request then it calls the view`() {
presenter.onCallViewRequest()
verify(view, times(1)).doSomething()
}

interface TestView {
fun doSomething()
}

class TestPresenter : BasePresenter<TestView>() {
fun onCallViewRequest() = view?.doSomething()
}
}

0 comments on commit c41ea52

Please sign in to comment.