Replies: 2 comments 4 replies
-
The above sounds reasonable, however, it would probably require some data-mapping and conversion when accessing the DB. Then, queries often require parameters. val db = ...
db.query(
"""
select ... from ... where id = ? and name = ?
""".trimIndent(),
id,
name,
) { rs ->
...
} That use pattern works well for encapsulating parameter conversion logic (e.g. the way different datatypes should be converted to DB), and it ensures If you start asserting on Here's another sample: expectSoftly {
data class MappingApplyResult(
val explainPlanUid: Id<ExplainPlan, Uid>?, //
val throwable: Throwable? // null on success
)
// explainMappingApply returns Map<String, MappingApplyResult>
// where the key is database name and the value is the result at that database
expect(configManager.explainMappingApply(failOnError = false)) {
notToBeEmpty()
// There should probably be Expect<Map<K, V>>.toHaveElementsAndAll(...Expect<Map.Entry<K, V>>...
asEntries {
// I can assert key and value independently, however, what I need is
// to load "value" for every "key"
toHaveElementsAndAll {
value.throwable.notToEqualNull()
.message
.because("test configured the system to fail") {
toContain("break explain plan to check if it properly shows FAILED status")
}
// How would I load the data?
// I need to access both key and value, so the only way out is "feature(...)" :-/
// However, it results in a quite involved "feature"
feature({
val dbName = key
val applyPlan = value
// assertManager is an injected service for database asserts and queries
assertManager.at(dbName) { qe ->
qe.query(
"""
select state
from session_traces t
where t.explain_plan_uid = ?
""".trimIndent(),
{ rs ->
// I don't quite like the idea of manually serializing resultSet data
// for the sole purpose of expecting it later
while (rs.next()) {
expect(rs.getString("state")).toEqual("FAILED")
}
},
applyPlan.explainPlanUid.id
)
}
}) {
// empty? all expectations are in "feature" above
}
}
} This time the query is trivial, and in theory, I can return "state" as a feature result, and then run an expectation. I wonder what you think of having something like fun <T> Expect<T>.unwrapSubject(
description: String,
action: T.() -> Unit
): Expect<T> =
apply {
when (val subject = _logic.maybeSubject) {
is Some -> subject.value.action()
is None -> _logic.createAndAppend(Untranslatable(description), null) { false }
}
} so the code could be like toHaveElementsAndAll {
value.throwable.notToEqualNull()
.message
.because("test configured the system to fail") {
toContain("break explain plan to check if it properly shows FAILED status")
}
unwrapSubject("Session in database should be in FAILED state") {
val dbName = key
val applyPlan = value
// assertManager is an injected service for database asserts and queries
assertManager.at(dbName) { qe ->
qe.query(
"""
select state
from session_traces t
where t.explain_plan_uid = ?
""".trimIndent(),
{ rs ->
// It looks like I can use expect(...) for expecting the columns
// TODO: add an expectation that the query returns exactly one row
while (rs.next()) {
expect(rs.getString("state")).toEqual("FAILED")
}
},
applyPlan.explainPlanUid.id
)
}
}
} Even though |
Beta Was this translation helpful? Give feedback.
-
Just that you know, I have never worked with ResultSet so far and I just made some assumptions without really looking at the documentation.
I assumed
I guess I see your point, but I am not entirely sure. Because if you would use the mapping in your example then you would not leak more than now. But I assume you refer to the case if you would have passed rs somehow as subject, right?
So far I have not seen many cases where we need this functionality on Map. That's why there is currently no shortcut function and one has to go over
That was my "fear", that if someone works with ResultSet the eager loading all rows and map into a data class approach might not be what such a person is used to, because in the business code it usually matters performance wise. I guess it does not matter in tests unless you want a fail-fast behaviour, i.e. stop at the first row which does not hold all expectations. For such a case my suggested approach is not feasible.
I am not yet sure if we should put it on the API level as it will pop up for any
This would be covered with the asList approach: qe.query(
"""
select state
from session_traces t
where t.explain_plan_uid = ?
""".trimIndent(),
{ rs ->
expect(rs).asList().toContainExactly {
get<String>("state").toEqual("FAILED")
}
},
applyPlan.explainPlanUid.id
) A flash thought, maybe it would make more sense to type the columns during the
Yet, if you deal with many columns, then using column1...n is not that readable. Last but not least, in the end I (we) won't add any ResultSet functionality which you don't intend to use. You are the only user I am aware of using Atrium in combination with ResultSet so far, so we should focus on functionality which will actually improve your work with Atrium 🙂 |
Beta Was this translation helpful? Give feedback.
-
As pointed out by @vlsi
As long as one does not intend to get data via
get...Stream
functions, then it could be OK to load all data eagerly and turn the ResultSet into aList<Columns>
where Atrium performs the mapping andColumns
is a data class provided by Atrium.I would then provide an extension function
get<T>(string|Int)
.The benefit would be that one can re-use all the functionality we provide for Iterable, i.e. all toContain functions as well as
toHaveElementsAndAll
etc.An example:
And the output then could look as follows:
If the naming in the reporting bothers us too much, then we cold improve it later on IMO, i.e.
elements need all
could be turned intorows need all
andindex 4
would berow 4
.The benefit of using this approach is that a developer sees more context (i.e. all columns not just the one where a comparison fails) giving good hints why something fails.
Another example:
Would look like something along the line of in reporting:
@vlsi WDYT would that be valuable for you and would it solve your issue regarding
peek on the current state
?Beta Was this translation helpful? Give feedback.
All reactions