-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SECTION execution regression #191
Comments
The first line is a bit unexpected, but the rest is by design as far as I can see: CATCH will treat all code at higher levels as initialisation code and re-run it for every SECTION at the same or lower level. I use this to re(set) fixtures in between sections. |
Hi Wichert! Yes, what you describe is the pre-1.0 behavior. Currently however, each TEST_CASE and SECTION is first run without any sub-SECTIONs, and I can't see how this would be useful. The problem is more obvious when using the BDD macros: SCENARIO("catch/nestedSectionsBDD")
{
printf("0");
GIVEN("s1") {
printf("1");
WHEN("s2") {
printf("2");
THEN("s3") {
printf("3");
}
}
}
printf("\n");
} There is no good reason this should print anything but: 0123 Or is there? |
There isn't any that I can see. For what it's worth I would prefer a more explicit style, but I think Phil disagrees with that. Something like (naming shamefully stolen from Jasmine: TEST_CASE("my-case") {
MyFixture fixture;
BEFORE_EACH() {
....
}
AFTER_EACH() {
fixture.reset();
}
SECTION(...) {
....
}
} This makes it explicit which code you want to run before/after every test (the after option is missing right now), and allows you to do one-time setup code that doesn't need to be rerun for every test. |
@stefanholek I rewrote the section tracking code. The old code was crufty and a bit too convoluted for something that's pretty central to how Catch works - and it had at least two known serious bugs. In doing so I changed the order that sections are scanned and run as this was a big part of the complexity. Previously I was aiming to run everything the minimum number of times - which is why your second example (nested sections) ran through in a single execution. Now it runs each level through entirely, noting nested sections as it goes - then goes back and runs the nested sections in the same way. This is much more uniform, runs consistently (even with errors) and is easier to reason about. Most of the time you won't notice the difference. Obviously instrumenting the tests with printfs or such shows it up. Does this give you any issues or was it purely curiosity? One of my future plans is to suppress output from any assertions that have already successfully passed on the way to running new sections - so this should minimise unnecessary output - but the code will still be executed. @wichert I prefer the more natural scoping that nested sections provides, yes. The only thing about it that is different to what you might immediately expect is the way only a single leaf section is executed at a time.
Since (1) is how I generally approach all my C++ code anyway this has not really been a problem for me. But I realise that there are different coding styles. Have you really found this an issue in practice? Finally - don't forget you can still do "tradtional" style fixture classes - with setup constructors and teardown destructors. Just use |
No issues. I just noticed my assertion count going up after upgrading Catch and was wondering. It's bound to increase test runtime though, especially for the BDD case, isn't it? |
Technically it will increase test time when you're using sections, yes. In practice this should not normally be noticeable - at least for unit tests. If you're using Catch for integration tests and your setup is expensive I can see this might be a bit more annoying - good point. I might take another look and see if I can start from what I have now and change it to depth first, again. If I can do so without re-introducing too much extra complexity I'll consider that. Thanks for the prod. |
I believe I just spent an hour or so discovering this bug. I pulled build 6 yesterday and most of my tests work fine. I then was running some newer tests today that already used the new BDD macros. Suddenly tests that I thought should work were failing. I didn't immediately think to connect the failures to Catch's build 6 and spent some time scratching my head instead. Here's what one of my tests looks like https://gist.github.com/bkuhns/135c079e0248a752c948 With build 5, this test passes normally. Under build 6, the mocking framework reports that the expected function (DataConverter::convert) isn't called. It seems the mocks get destructed differently in Catch build 6 such that methods on them aren't invoked first, so the mocking framework throws an exception. Update: It seems in build 6, the GIVEN section where I set up the mocks and their expectations doesn't delve into the WHEN section during the same execution step, so the mock(s) get destructed without the expected functions called. |
I just pulled build 23 and this behavior still exists. Here's a "real world" example of using regular sections rather than the BDD macros. I create a mock object in my set up, each section then sets different expectations on the mock, the actual test runs after the sections, and finally we set up the requirement on the result: TEST_CASE("Connector should or shouldn't send a message depending on whether it's connected.")
{
auto implMock = new ConnectorImplMock();
auto connector = Connector(unique_ptr<ConnectorImpl>(implMock));
SECTION("Connector is connected.")
{
MOCK_EXPECT(implMock->isConnected).once().returns(true);
MOCK_EXPECT(implMock->send).once();
}
SECTION("Connector is NOT connected.")
{
MOCK_EXPECT(implMock->isConnected).once().returns(false);
MOCK_EXPECT(implMock->send).never();
}
auto message = getDummyMessage();
connector.send(message);
REQUIRE_NOTHROW(mock::verify());
} Somewhere around build 4 or 5, CATCH would go immediately into the first SECTION on the first run. With build 23, it skips both sections and executes the test. But because the mock's expectations are set within the sections, the first run of the test (which skips sections) executes without setting up the mock. With no expectations set, the mock framework throws an exception on the first run of the test. This makes sections in a unit test with mock objects unusable. |
Prompted by #552 I had a look through this issue again. |
Just started using catch 1.5.1 today for integration tests, and immediately stumbled upon this issue. |
Hi @ruderik1, |
Hi Phil, |
Since nobody else (other than @ruudsieb) chimed in on this thread in the intervening couple of years I'm going to assume that there are no outstanding issues? |
Looks good to me, I just tried out the following test: TEST_CASE("A SECTION should be run on the first pass.")
{
auto sectionRun = false;
SECTION("If this section runs, then the test should always succeed.") {
sectionRun = true;
}
REQUIRE(sectionRun);
} And the test passes, implying it runs through the section on the first run. |
Cool - thanks @bkuhns |
Given this test:
Pre-1.0 the output used to be:
01
02
03
With current tip the test prints instead:
0
01
02
03
More curiously, given this test:
Pre-1.0 the output used to be:
0123
While with current tip the test prints:
0
01
012
0123
The text was updated successfully, but these errors were encountered: