Expect
Represents the extension point for expectation functions and sophisticated builders for subjects of type T.
Following a simple example, see Write own Expectation Functions for more help:
val <T: SQLException> Expect<T>.errorCode: FeatureExpect<T, Int>
get() = feature(SQLException::getErrorCode)
Note, that we have used a type parameter and not Expect<SqlException>
. This is due to the fact that Expect
is invariant which means without type parameter something like the following would result in a compile error
expect {
...
}.toThrow<BatchUpdateException> {
errorCode.toEqual(23000)
// compile error: None of the following candidates is applicable because of receiver type mismatch:
}
Besides, we would need to return a FeatureExpect<SQLException, Int>
and would therefore lose the information that the thrown Exception was a BatchUpdateException
and would first need to use toBeAnInstanceOf<BatchUpdateException>
if we want to assert something which is specific to BatchUpdateException
. With the type parameter we don't and could therefore then also write something like the following within the toThrow
block:
feature(BatchUpdateException::getUpdateCounts).toEqual(intArrayOf(3, 2))
In general, you should always use the type parameter approach, the only exception is if you deal with final classes (e.g. data classes) which don't have a type parameter itself. In such a case there is no benefit to have a type parameter but on the other hand, it also doesn't hurt -- less to think about (your IDE might warn you that it is not necessary though).
As a side notice, we have not defined Expect
as covariant on purpose (switched to invariant in v0.9.0), because if we did, then things like expect(1).toEqual(1.0)
would no longer be a compile error. And Atrium's goal is exactly to prevent users from pitfalls like that.
Parameters
The type of the subject of this
expectation.