nagare

Nagare (流れ) is japanese and means "flow" / "stream". This is an assertion/matcher library for kotlin using infix functions. It is easily extendable using extension functions. You can use it with both junit or testng.

Setup

In order to use this library you need a github account and a repository read token. When logged-in open the personal access tokens page. Create a new token having read:packages as the only permission.

Gradle - kotlin-dsl

Add the repository to your existing list of repositories:

repositories {
maven {
name = "nagare"
url = uri("https://maven.pkg.github.com/cc-jhr/nagare")
credentials {
username = "your-github-username-here" // you should probably use environment variables
password = "your-github-packages-read-token-here" // or gradle properties here to inject the values
}
}
}

Add the dependency to your dependencies block:

dependencies {
testImplementation("io.github.ccjhr:nagare:VERSION")
}

Usage

Origin of a test is the object itsef. The object must satisfy criteria

    @Test
fun `usage test`() {
12 mustSatisfy {

}
}

Various criteria can be described depending on the class type. Int for example provides functions like isGreaterThan/isLesserThan.

    @Test
fun `usage test`() {
12 mustSatisfy {
it isGreaterThan 6
it isBetween 10..20
}
}

Nullability can be checked using additional adjectives:

    @Test
fun `usage test`() {
val obj: String? = null

obj mustSatisfy {
it isNot Null
}
}

Checking a parameter of a more complex object can be achieved using a nested mustSatisfy block:

    @Test
fun `usage test`() {
val obj = MyObj(12, "", emptyList())

obj mustSatisfy {
it isNot Null
it isOfType MyObj::class

it.content.number mustSatisfy { number ->
number isEqualTo 12
}
}
}

data class MyObj(
val number: Int,
)

Individual extensions

Lets assume we have an individual object.

data class MyObj(
val title: String = "",
val number: Int = 0,
)

Based on values

The extension function itself always has a similar structure. In the signature we place our object type as well as the class type that we want to test against and give the function a name. Check for nullability. It's possible to make this non-nullable, but then you would have to use !! operator or a kotlin function which uses contracts like requireNotNull if your resulting object is nullable.

inline infix fun <reified T : MyObj?> AssertionContext<T>.hasTitleMatching(regex: Regex) {
expectNotNull(this.content)

if (!regex.matches(this.content.title)) {
fail("Expecting title <${this.content.title}> to match <${regex.pattern}>, but it doesn't.")
}
}

Then we can use it in a test.

@Test
fun `test the newly created extension`() {
// given
// setting up the test case

// when
val result: MyObj = // code that returns an instance of MyObj

// then
result mustSatisfy {
it hasTitleMatching Regex("[a-z]+-[0-9]+")
}
}

Based on adjectives

We can create extensions using adjectives by adding an enum class for the adjectives. Here we simply imply that the object is "valid" in a way.

enum class MyObjAssertionAdjective {
Valid
}

The only difference is that the extension function takes the enum class as parameter and we use a when to apply to the different cases.

Just for the demonstration we assume that the object is valid if it has a number greater than 0 and a title which is not blank.

inline infix fun <reified T : MyObj?> AssertionContext<T>.hasToBe(adjective: MyObjAssertionAdjective) {
expectNotNull(this.content)

when(adjective) {
Valid -> if (content.number <= 0 || content.title.isBlank()) fail("Object is not valid.")
}
}

Then we can use it in a test.

@Test
fun `test the newly created extension`() {
// given
// setting up the test case

// when
val result: MyObj = // code that returns an instance of MyObj

// then
result mustSatisfy {
it hasToBe Valid
}
}

Packages

Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard