-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce Kotlin Assertion Helper Library #924
Comments
Are there Kotlin-friendly assertions libraries you could use instead? |
There are a few. Many of them that provide full runtime syntax helpers piggyback off of Junit4. I've been using hamkrest for some nicer Are there any particular complexities of implementing your own Perhaps I just need to have something that throws the |
Yes, that's all you'd need. Do you want to give it a shot? |
@sdeleuze, since you've introduced several Kotlin improvements for Spring Framework 5.0, can you provide us any guidance here on how to achieve a nice user experience with Kotlin with the least amount of work on the JUnit side? |
Maybe this is something that If this is outside of the scope of the Junit mission statement I totally understand. I just wanted to run it by the devs here before charging off on my own path. Is the |
|
Since getting proper Kotlin support on assertion side is low hanging fruit + non intrusive, I would be super interested in getting a place inside https://github.com/junit-team organization to contribute a few Kotlin extensions, function or aliases for current JUnit 5 constructs. Would it be doable to create a IMO that would be a small addition to current API, but it would be super useful for Kotlin developers. On Spring side, I really would like to push JUnit 5 as a first class Kotlin JVM testing library, such extension would really help. Any thoughts? |
Hi @sdeleuze, That's awesome that you're interested in helping out with the Kotlin support! 👏 As for the logistics, are PRs too difficult for you in this regard? If so, I suppose the team will have to decide on how best to proceed. Cheers, Sam |
@sdeleuze, just to be clear... Are you only proposing to add Kotlin extensions for the Or are you proposing to add additional support for parts of the JUnit Platform or other parts of JUnit Jupiter? |
I am not sure yet about the scope, but I will be happy to bootstrap such module with |
Is it feasible to include Kotlin-specific class files in the junit-jupiter-api JAR? Or does it make more sense to create an additional artifact? |
Yes it is feasible and given the few kbytes needed, I would recommend that way, like we did on the Spring side. If you are ok with that, should I submit a PR (when I will be back from holyday) ? |
If we do that won't it require including the kotlin stdlib/reflection lib as a dependency? Or am I wrong? |
Nope, the principle would be to have 0 impact for Java developers except the few kb of bytecode, dependencies on |
We will have to make sure that all the Kotlin things are in separate classes, though, right? |
You could probably just use Kotlin's first class functions. I think when it gets compiled they get wrapped in their own static class (with the file name as the class name) (this is for java interop) but the kotlin language totally hides this. |
Indeed |
What configuration is |
Cursory look at what I've got so far. package org.junit.jupiter.api
import org.junit.jupiter.api.function.Executable
import org.junit.platform.commons.meta.API
import org.junit.platform.commons.meta.API.Usage.Experimental
import java.util.stream.Stream
internal typealias ExecutableStream = Stream<() -> Unit>
internal fun ExecutableStream.convert() = map { Executable(it) }
/**
* @see Assertions.assertAll
* @since 5.0
*/
@API(Experimental)
fun assertAll(executables: ExecutableStream) = Assertions.assertAll(executables.convert())
/**
* @see Assertions.assertAll
* @since 5.0
*/
@API(Experimental)
fun assertAll(heading : String?, executables: ExecutableStream) = Assertions.assertAll(heading, executables.convert())
/**
* @see Assertions.assertAll
* @since 5.0
*/
@API(Experimental)
fun assertAll(vararg executables: () -> Unit) = assertAll(executables.toList().stream())
/**
* @see Assertions.assertAll
* @since 5.0
*/
@API(Experimental)
fun assertAll(heading: String?, vararg executables: () -> Unit) = assertAll(heading, executables.toList().stream())
/**
* @see Assertions.assertThrows
* @since 5.0
*/
@API(Experimental)
inline fun <reified T : Throwable> assertThrows(noinline executable : () -> Unit) : T =
Assertions.assertThrows(T::class.java, Executable(executable)) |
Is the use of this plugin on master? I'm not seeing it anywhere. Nor am I seeing the string |
@JLLeitschuh, the JUnit 5 build does not currently use any Gradle plugins from Spring; however, that doesn't mean we couldn't switch to that if we cannot find an alternative with our current build infrastructure. |
@JLLeitschuh I assume that |
Looking at https://docs.gradle.org/current/userguide/java_library_plugin.html, it looks to me that |
@JLLeitschuh Well, having said that, I realise now and admit that I don't understand the reason why you're after a configuration for "optional" or "provided" dependencies. Can you explain further? |
Reasoning: #924 (comment) |
@JLLeitschuh Okay, cool! Then yes, I would make a reasonable guess that |
Team decision:
|
FYI: we now use Spring's propdeps-plugin on Thus, this should be used for |
@sdeleuze and @JLLeitschuh, As you can see from the above "team decision," we'd like to know the pros and cons for having the Kotlin extensions published in the Can you two please expound on that? Keep in mind that we would ideally like to publish the Kotlin extensions as a separate artifact if possible. 😉 |
Using About where publishing the extensions, Kotlin does not require publishing them in the same artifact, but I do think it would make sense to ship them in |
I tend to agree! But one concern that the team has (which I forgot to mention -- sorry) is the topic of split packages. Please excuse our ignorance, but... Does a Kotlin extension have to reside in the same package as the Java class it is extending? In other words, if we package the Kotlin extension for Jupiter's |
Since we are already using Spring's So, just to clarify... Are are you saying you would recommend against using the |
It does seem like a very few methods to create an entirely new artifact for (6 or so methods).
I'm not actually adding extension methods to the So when you use the methods in kotlin code you import the method, not the class. // The kotlin version of `assertThrows`
import org.junit.jupiter.api.assertThrows
// The java version of `assertThrows`
import org.junit.jupiter.api.Assertions.assertThrows If I were using kotlin extension methods, for example if I wanted to expose a kotlin api on Here are some examples of extension functions not in the same package as the type they they are extending: package com.company.util.collections
import com.google.common.collect.ImmutableList
import com.google.common.collect.ImmutableSet
fun <T> Collection<T>.toImmutableList() : ImmutableList<T> = ImmutableList.copyOf(this)
fun <T> Collection<T>.toImmutableSet() : ImmutableSet<T> = ImmutableSet.copyOf(this)
operator fun <T> ImmutableList<T>.plus(elements : ImmutableList<T>) =
ImmutableList.builder<T>().addAll(this).addAll(elements).build()!! |
Doesn't using |
@sbrannen In fact split packages are another good reason for putting Kotlin JUnit extensions into the same JAR. Extension can live in the package you want, as described by @JLLeitschuh, but I think this is a good convention for users to make it live in the package of the class they extend. And since both @sbrannen @JLLeitschuh I have no strong opinion about using |
Hi guys, Thanks for chiming in! We'll take your feedback into consideration. |
Yes. But... we prefer for the generated Maven POMs to tell the whole story, namely that there is in fact a dependency which just happens to be optional. The complete absence of a declaration on a dependency in the generated Maven POMs does not convey the fact that such a dependency exists (even if only optional). |
Using the nice Kotlin version of
Switching to the Java version of Is there a build of JUnit targeting JVM 1.8 bytecode? |
That's how we configure the Kotlin compiler: Lines 190 to 196 in be331a4
|
Feature Request
This is mostly a "nice to have" syntactically but the current a select few methods that all take
[SomeWrapperType]<Executable>
don't play as nicely as they could in kotlin.Someone could easily create a kotlin DSL library wrapper over junit 5.
I did this with the Google Guice DI library creating Kotlin Guiced. I could just as easily do the same thing for Junit5 but if there is an interest it would be nice if the small DSL library was vendored by the Junit team.
The methods that I've currently found that don't play the nicest are the following:
assertAll(Stream<Executable> executables)
:In kotlin calling this method becomes:
This could be simplified by providing a method:
This would allow for the much nicer syntax:
assertAll(Executable... executables)
:In kotlin calling this method becomes:
This could be simplified by providing a method:
This would allow for the much nicer syntax:
Similar methods would need to be provided for the methods that take
String header
as well.assertThrows(Class<T> expectedType, Executable executable)
Calling in Kotlin it becomes:
Yeay! We get auto conversion because this method takes
Executable executable
not a collection. However theIllegalArgumentException::class.java
is kind of clunky.This one could use reified types to make this nicer!
If we provide a method:
Then the syntax to call it in kotlin becomes:
Note
These problems don't exist with all methods that take
Executable
.For example, this is completely valid given the current Junit5 API:
Deliverables
junit-jupiter-kotlin-api
.junit-jupiter-kotlin-api
library.The text was updated successfully, but these errors were encountered: