I like the mutable DSL. What I don't like is the fact that there are so many variants of it. This makes Specs a very difficult framework to teach to newcomers (similar to ScalaTest), since there are so many options. I personally prefer should
/to
, but there are a lot of caveats with that syntax. Instead, I think it's better to just settle on >>
(or some variant thereof). It keeps the best feature of the mutable fragments construction (easy arbitrary nesting) without generating the linguistic or API ambiguity of the current menagerie.
I would remove the immutable specification definitions entirely.
Specs2's absolute best feature is Matcher
and the ability to easily define your own. I would lean into this by making it even easier and more uniform. The implicit coercions are cute, but not particularly reliable and honestly not as helpful as a nicer set of Matcher
companion constructors would be. Literally just an apply
on the Matcher
companion object which takes a function would probably be enough.
With that said, there are some annoying warts that you run into often when defining custom matchers. The biggest one is that it's very difficult to define a custom matcher which itself delegates to some other matcher. You end up decomposing Result
by hand, which is a pain to say the least. As a note, this kind of delegation often comes up when you're trying to get access to nicer error messages from the delegate matcher, particularly with beLike
(which is absurdly useful).
I'm not sure exactly what to do here or how to improve this situation, but it's probably the single most significant place where the Specs API needs a revamp.
I use mustEqual
all the time. I don't think that I should. I think I should be forced to use must equal(value)
. The magic associated with must
and must be
and all that is really complicated, and I think it would be a lot saner if Specs abandoned the literate DSL concept and just stuck with "result must
matcher".
Doing stuff like this is very unpleasant. Tests which run in Future
should be the default mode of operation, with eager tests being a special case of this. This is obviously exactly how the Fragments
framework behaves behind the scenes, but it should be a little easier to exploit this directly in user-space.
Also I didn't know about AsFragments
until after I wrote that code; don't at me. ;-)
Ideally, I'd like to be able to write a really seamless Cats Effect integration which makes it extremely convenient to write Specs tests in IO
such that they run across both JVM and JS, and with the same performance characteristics as frameworks like Weaver.
This is a rough one, since ScalaCheck is ScalaCheck, but this might help: https://github.com/typelevel/scalacheck-effect I'm not sure if this should just stay third-party or be pulled in first-party, but it's important.
Discipline defines a function, checkAll
, which takes a law set (which is fundamentally a set of scalacheck properties) and introduces it to Specs so that it can be run as a set of fragments. The definition is here.
In and of itself, this function doesn't behave too poorly, but it does end up being more annoying that working with specs2 directly in some subtle ways. It's surprisingly difficult to get it to respect the Parameters
, for example (you generally have to pass it explicitly), meaning that Seed
integration is relatively weak. I'm not sure why that is. It also seems to run all of the laws strictly sequentially in most cases, though I say "seems to" because I've seen circumstantial hints in both directions. Either way it's weird. Output for law sets appears to be buffered when Test / fork := false
, though unbuffered when it's true
(meaning you get incremental output as each law passes), so I don't really know.
Maybe there's nothing to be done here. It's worth thinking about a bit, I think.
I realize this is entirely at odds with the "I like the mutable DSL" bit. :-P Sometimes (like with Discipline), you really need to be able to generate fragments programatically and have them behave as proper fragments, with appropriate line numbers and everything. This is somewhat challenging to do right now. Yes, I realize that a lot of that is because I'm using the mutable DSL. :-)
The situation doesn't come up that often, but just as matchers allow abstraction at the assertion level, it would be nice if there were a similarly powerful and easy-to-use abstraction for abstraction at the test level.
I seriously still have to look up the syntax for pending
, pendingUntilFixed
, skipped
, etc. They aren't uniform, which makes it a lot more complicated. Also the fact that pendingUntilFixed
works in the mutable DSL if you use a .
to attach it to the curly brace block, but not if you omit said .
and allow it to associate as a postfix method. It's very odd.
I'd really just like a uniform syntax for all of them. Something that allows me to easily wrap/unwrap a fragment in the marker.
Before
/After
and friends are really complicated and I can never remember how they work. They're also very imperative. They're also completely in opposition to things like Cats Effect's Resource
, making it very difficult to even implement a nice integration framework between the two.
I feel like being more explicit about the types here would probably help. Like if you define a setup
, it must return something of type R
, which is then optionally available as a parameter to all fragments. Similarly for something like setupEach
. I'm not sure.