scripted tests and their design #8338
Replies: 2 comments
-
scripted test existed ever since I was one of plugin authors (I wrote https://eed3si9n.com/testing-sbt-plugins/ in 2011 as a user), long before I became the maintainer, and I sort of took for granted that "this is the way it's done", so your perspective is refreshing. So thanks for the input. Re: "native". I don't know if discussing what is and isn't "native" is all that productive. We can easily flip your argument saying that JUnit or ScalaTest style unit testing is (albeit popular) a generic solution, meanwhile scripted test is a purpose-built, integration testing framework that is native to sbt and the incremental compiler Zinc to emulate file changes interspersed with human command invocations. If you've worked with Scala compiler on scala/scala, you might also discover that they also have a bespoke integration testing called Partest (which I also documented in https://github.com/scala/scala/blob/2.13.x/CONTRIBUTING.md#partest). Similar to scripted, basically you create some example files, and expected positive or expected-negative outputs from the compilation. These file-based integration ("functional") testing is useful for tooling maintainers (like sbt, Zinc, and Scala compiler core devs and contributors) because we often get bug reports in the form of files, and we communicate with each other in the form of files with varying degree of minimization. And there are probably hundreds of tests in these repos captured this way. For example: $ find sbt-app -name test | wc -l
528So some plugin authors, including myself, have started to advocate for its usage for plugin testing, riding on the shoulder of existing investment. I think reevaluating the usage of unit test framework for integration testing is an interesting idea, and something interested party can explore. server-testProbably the closest thing in sbt/sbt already might be the way we test sbt server, since we launch an instance of sbt server in a temp directory, initialized using files in test("build/initialize") {
val id = initializeRequest()
assert(svr.waitForString(10.seconds) { s =>
s.contains(s""""id":"$id"""") &&
s.contains(""""resourcesProvider":true""") &&
s.contains(""""outputPathsProvider":true""")
})
}I don't know if it has the best developer experience, and it could be just as flaky as scripted test if not more. miscellaneous concerns
|
Beta Was this translation helpful? Give feedback.
-
|
Thank you for your quick and detailed response! I don’t think we need to completely replace By "native", I meant that everyone is already familiar with writing tests using frameworks like JUnit or TestNG, which look and run the same way across most JVM ecosystems, and using a similar approach for testing plugins would feel more natural and easier for people to get started with. Besides implementing some kind of |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Hello! Recently, I had to write some scripted tests, and here I want to discuss their design and how they work.
To begin with, I have to say that they look like a non-native solution right from the start.
sbt-testdirectory, which isn’t supported by Metals or IntelliJ IDEA. It’s a completely separate directory and it's a pain to write tests there.scriptedruns. You’re also responsible for passing the correct version, which must be done with something likescriptedLaunchOpts += version.apply(v => s"-Dproject.version=$v").value.build.sbt.In Gradle’s implementation, they suggest an approach that doesn’t really differ from writing standard unit tests. In short, you write test cases that run a Gradle build using the
GradleRunnerclass in a temporary directory, which you populate with the required contents directly within the test case.This approach allows you to:
afterEach,beforeEach, and more features currently missing from the scripted tests implementation.build.sbttasks, since you can now write it directly in your test case file. This also makes it easy to share code between tests. And no more mini-DSL.As for me current scripted tests implementation feels very flaky. Gradle's approach feels much more like a native solution. What do you think?
Beta Was this translation helpful? Give feedback.
All reactions