Our case classes have several require
statements to throw exceptions when they receive malformed input. This is normally pretty helpful, but can make writing property-based tests a pain, since we have to write generators that satisfy all the requirements rather than simply using the built-in generators. Is there an easy way to set Scala to ignore require statements during testing?

- 271
- 1
- 2
- 9
-
*[...] we have to write generators that satisfy all the requirements rather than simply using the built-in generators*. Why would you not ensure that the generators you use produce instances that satisfy the class's invariants? Besides, you should consider eschewing `require` altogether (as you point out, it throws exceptions, so it isn't very functional) and centralising validation and instantiation of `Foo` in a creation method that returns a `Try[Foo]`. – jub0bs Dec 23 '16 at 11:38
2 Answers
A much better approach would be to avoid require
entirely, and instead write smart constructors that return Either
(or Validation
if you're scalaz-inclined.) Better still would be to create newtype wrappers (i.e. case class MyWrapper private (i: Int) extends AnyVal
) for your input types, where those wrappers come with smart constructor such that only valid values can be constructed. When you write generators for these bespoke types, you can ensure that the invariants you need are preserved.
Rather than look for a way around the type system (by using require
to throw exceptions at runtime) let the type system work for you. This will make not only writing your property-based tests much easier, but the entirety of your system will benefit.

- 4,560
- 1
- 26
- 29
-
Interesting, `Validation` seems like the way to go for my use case–the require statements aren't *super* important, and simply logging the errors is probably good enough. I'm mostly trying to avoid writing *any* generators though, because we have enough datatypes that it would be a really substantial undertaking. – Satvik Beri Nov 02 '16 at 04:53
-
1I'm curious... Could you expand on "Better still would be to create newtype wrappers (i.e. `case class MyWrapper private (i: Int) extends AnyVal)` for your input types, where those wrappers come with smart constructor such that only valid values can be constructed." +1, BTW – jub0bs Dec 23 '16 at 11:46
No - require
is a very simple method, as you can see from the source:
def require(requirement: Boolean) {
if (!requirement)
throw new IllegalArgumentException("requirement failed")
}
@inline final def require(requirement: Boolean, message: => Any) {
if (!requirement)
throw new IllegalArgumentException("requirement failed: "+ message)
}
I'd suggest providing a separate way to construct your class that only the tests use. For example, if you scope the constructor to the package:
package foo
final case class Foo private[foo] (...)
object Foo {
def apply(...): Foo = /* put assertions in here */
}
Then you could put your scalacheck generators in the same package and let them use the private constructor.
Or if you really want to get weird with it, you could write your own require
that determines whether to skip the checks based on some global state or an implicit parameter. But this seems unwise.

- 30,334
- 10
- 78
- 137
-
*I'd suggest providing a separate way to construct your class that only the tests use.* I vigorously disagree. If your tests are bypassing the application code, what's the point? Controlling instantiation using a factory/creation method in application code, and using that method in generators is the way to go, IMO. – jub0bs Dec 23 '16 at 11:42