IBlockListener per block, not BlockKind / precise block logging
ptomaszek opened this issue · comments
Is your feature request related to a problem?
Yes - precise logging of particular block's text is not possible.
Describe the solution you'd like
Example code:
Repo with working example: https://github.com/ptomaszek/spock-IBlockListener
./mvnw test
Spock test:
def "test"() {
given: "given 1"
log.info("given 1 custom log ")
and: "given 2"
log.info("given 2 custom log ")
expect: "expect"
log.info("expect custom log ")
}
Listener and extension setup:
class IBlockLoggingExtension implements IGlobalExtension {
@Override
void visitSpec(SpecInfo spec) {
spec.addListener(new BlockLoggingRunListener())
}
class BlockLoggingRunListener extends AbstractRunListener {
@Override
void beforeFeature(FeatureInfo feature) {
feature.addBlockListener(new BlockLoggingListener())
}
}
class BlockLoggingListener implements IBlockListener {
@Override
<S extends Specification> void blockEntered(S specificationInstance, BlockInfo blockInfo) {
def logger = LoggerFactory.getLogger(specificationInstance.class)
logger.info("{}", blockInfo.getTexts().join("; "))
}
}
}
What happens:
[main] INFO org.example.IBlockListenerSpec - given 1; given 2
[main] INFO org.example.IBlockListenerSpec - given 1 custom log
[main] INFO org.example.IBlockListenerSpec - given 2 custom log
[main] INFO org.example.IBlockListenerSpec - expect
[main] INFO org.example.IBlockListenerSpec - expect custom log
What I would like to happen:
[main] INFO org.example.IBlockListenerSpec - given 1
[main] INFO org.example.IBlockListenerSpec - given 1 custom log
[main] INFO org.example.IBlockListenerSpec - given 2
[main] INFO org.example.IBlockListenerSpec - given 2 custom log
[main] INFO org.example.IBlockListenerSpec - expect
[main] INFO org.example.IBlockListenerSpec - expect custom log
High level proposal
Extend IBlockListener
with blockPartEntered
and blockPartExited
methods. An implementaion similar to the following should be possible:
@Override
<S extends Specification> void blockPartEntered(S specificationInstance, BlockPartInfo blockPartInfo) {
def logger = LoggerFactory.getLogger(specificationInstance.class)
logger.info("{}", blockPartInfo.getText())
}
Describe alternatives you've considered
I am aware of the _
workaround (def _(def message) {...}
) mentioned in couple of places, but I believe this is just a workaround, not the proper solution.
If Spock distinguishes blocks, then in should support proper block listener, not only block-kind listener.
Additional context
By looking at historical PRs and issues, I believe this request is valid to be considered for precise logging and possibly other custom aspects.
References:
As I mentioned in the SO question you linked to, and:
does not start a new block, it is just a visual separator with the possibility to add another text to the current block in all aspects. For example if an implicit try-catch is added for a whole block, it is added for the whole block.
The listener is not called for block types, but for real blocks. If you for example have multiple then
blocks to also assert on interaction usage order, the listener is called for each of them separately.
If you for example have multiple then blocks to also asset on interaction usage order, the listener is called for each of them separately.
This is possible:
...
then: "then 1"
then: "then 2"
and: "then 3"
This is not:
given: "given 1"
given: "given 2"
and: "given 3"
So maybe the solution would be to allow for multiple given
blocks?
For your specific use-case, probably.
But whether that is a strong enough reason to allow such block-repeatings I'm not sure.
I leave this to @leonard84 for considering.
But then the next user (or you later on) comes and wants the same for expect
, and when
, ... 🤷♂️
I'm not sure whether we should weaken the syntax just for benefitting the block listeners.
I'm not sure whether we should weaken the syntax just for benefitting the block listeners.
It may affect behavior in ways that are hard to predict, I guess.
For my case I'd be happy to have IBlockListener
extended with additional blockPartEntered
and blockPartExited
methods that would run for visual separators and blocks. For now I'll assume this is too challenging as well.
Anyway, thank you for taking the time to reply.
Feel free (you or @leonard84) to close the ticket with appropriate status
I'm disinclined to complicate an already really complicated part of Spock, but for the sake of argument I'd be interested in the use case(s) for this @ptomaszek.
I'm disinclined to complicate an already really complicated part of Spock, but for the sake of argument I'd be interested in the use case(s) for this @ptomaszek.
- The main use case is logs analysis, as in the example in the initial message.
Maybe one day enhancing Allure reports by presenting block descriptions as the steps without explicit use ofsee EDITAllure.step(...)
.
In my company we set up Spock + Allure for end-to-end tests. Each test consists of many steps that are nicely segregated and documented by Spock blocks. But this is of limited value when analyzing logs in case something goes wrong in CI pipeline.
I understand your concerns about the request and expect no further work around it. But anyway, thanks for reaching out
EDIT:
I just checked that Allure separates blocks and adds descriptions as naturally expected:

I believe Allure doesn't rely on listeners, so there must be some other mechanism for distinguishing blocks.
Spock2+Allure example: https://github.com/ptomaszek/spock-IBlockListener/tree/allure