Testing - TradeMe/Plunge GitHub Wiki
Due to the strict nature of how matching is done with this new pattern language, all we need to do is ensure
that an input URL (in the form of a Uri
) matches our pattern definition. For this, we can instantiate our handlers and test their matchers against an input URI in just a few lines of code.
Using Plunge to test deep link handling
Plunge includes two optional, though recommended, dependencies for helping you test your apps deep link handling. These modules allow you to not only test your pattern
implementation, but also check to make sure your app actually handles the correct URLs from an intent-filter
level.
Defining test cases
Test cases for Plunge are defined in JSON files. This allows Plunge to access these test cases at both a pattern-matching level and intent-filter
level in a unified way. A sample test case may look like this:
{
"url": "https://plunge.example.com/submarines/12345/buy",
"description": "The page for buying a submarine",
"params": [
{
"name": "id",
"value": "12345"
}
]
}
Here we define the URL to test, with a human readable description. We also define params, which is what we expect our pattern
s to match on and extract.
These test cases should be added to a new directory in the test
source directory in your app module – for example, src/test/test-cases
. See the sample project for our recommended approach.
plunge-test
for testing patterns
Using You'll need to ensure you've added the following dependencies to your app's test configuration in the module-level build.gradle
(if you've included all the dependencies from the README, you'll have this set up already):
testImplementation 'nz.co.trademe.plunge:plunge-test:current_version'
testImplementation 'nz.co.trademe.plunge:plunge-parsing:current_version'
You'll then need to set up one parameterized unit test to cover all the test cases. An example looks like this (from the README):
@RunWith(ParameterizedRobolectricTestRunner::class)
@Config(manifest = Config.NONE)
class PlungeExampleTests {
companion object {
@JvmStatic
private val pathToTests = System.getProperty("user.dir") + "/src/test/test-cases"
@JvmStatic
@ParameterizedRobolectricTestRunner.Parameters(name = "{0}")
fun parameters() = PlungeTestRunner.testCases(pathToTests)
}
val linkHandler = DeepLinkHandler.withSchemeHandlers(
PlungeExampleSchemeHandler(Mockito.mock(DeepLinkRouter::class.java))
)
@ParameterizedRobolectricTestRunner.Parameter(0)
lateinit var testCase: PlungeTestCase
@Test
fun runTest() = PlungeTestRunner.assertPlungeTest(testCase, linkHandler)
}
You can essentially take this example and plug it directly into your project, and just replace the pathToTests
and linkHandler
with your own test path and DeepLinkRouter
respectively (note that the example also depends on Mockito – if you're not using Mockito in your project, you can instantiate a stub object here instead). But let's break down what's going on here anyway. There are 3 main components:
- The
parameters()
function: a static function annotated with@ParameterizedRobolectricTestRunner.Parameters
allows the Robolectric test runner to build up the test cases. The providedPlungeTestRunner
class has a static function calledtestCases
which processes all the JSON files and returns the collection of test cases in the format the Robolectric test runner expects. You can change the value ofname
attribute of theParameters
annotation, but note that there is only one object (aPlungeTestCase
) in the test case parameters (i.e. only{0}
is available to be used). See this section from the JUnit wiki for more info. - The
testCase
field: a field of typePlungeTestCase
, annotated with@ParameterizedRobolectricTestRunner.Parameter(0)
. This is the field which holds each test case for the parameterized test case to execute against. - The
runTest
function: a function annotated with@Test
. This is a standard JUnit test which runs the current test case using thePlungeTestRunner.assertPlungeTest
function. The link handler gets passed in here, and test test cases are run.
plunge-gradle-plugin
for testing your intent-filter
s
Using For this part, you'll need to ensure you've added the following dependencies to your app's test configuration in the module-level build.gradle
(if you've included all the dependencies from the README, you'll have all this set up already):
buildscript {
dependencies {
classpath "nz.co.trademe.plunge:plunge-gradle-plugin:current_version"
}
}
dependencies {
// ...
testImplementation 'nz.co.trademe.plunge:plunge-parsing:current_version'
}
You'll also need to ensure you apply the plugin and provide a path to your test cases.
apply plugin: nz.co.trademe.plunge
plunge {
testDirectory = file("$projectDir/src/test/test-cases")
}
After a Gradle sync, you'll notice a few new tasks pop up in the verification
section for your app, prefixed with plungeTest
. Running these tasks will build and deploy that variant of your app to the device attached, and then run the test cases against that installation of the app to ensure the app handles the URLs you expect it to (but doesn't handle the URLs you don't want your app to handle!).
An example of a positive test case was provided above in the section Defining test cases; a negative case might look like the following:
{
"url": "https://plunge.example.com/submarines/help/buy",
"description": "The help page for buying a submarine; we don't support this in the app yet",
"handled": false
}
There are a couple of subtleties to be aware of when using the Gradle plugin:
- The release variant of the
plungeTest
task may not build and deploy your application first. If this is the case, simply ensure you have the release variant installed. - For the verification to work, you must ensure only one device is connected in debug mode before running the test. This is due to the fact that it queries a specific device for URLs handled.