Skip to content
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

BeforeAll/AfterAll? #70

Closed
modocache opened this issue May 12, 2014 · 27 comments
Closed

BeforeAll/AfterAll? #70

modocache opened this issue May 12, 2014 · 27 comments
Labels
v2 Issues that will be resolved by v2

Comments

@modocache
Copy link

First of all, thanks so much for this library. It really makes testing in Go a joy.

RSpec includes before(:all) and after(:all) nodes. These nodes are executed once at the beginning or end of an example group, respectively:

require 'rspec'

RSpec.describe 'before and after all nodes' do
  before(:all) { puts "\nbefore(:all)" }
  after(:all) { puts "\nafter(:all)" }
  it 'is an example' { }
  it 'is another example' { }
end

When run, rspec outputs:

before(:all)
..
after(:all)

I was surprised that Ginkgo does not include BeforeAll or AfterAll functions. Is this a conscious omission? Would you consider a pull request which adds these functions?

@onsi
Copy link
Owner

onsi commented May 12, 2014

hey @modocache,

The lack of BeforeAll and AfterAll is intentional, and I'd be curious to see the usecases you have in mind that necessitate it.

*All variants incentivize sharing state across Its -- this is generally not a good idea.

Because Its do not share state Ginkgo can treat them as completely separable uncorrelated entities. This allows Ginkgo to --randomizeAllSpecs - an important feature for sussing out test pollution. It's also the core principle behind Ginkgo's parallelization strategy. The *All variants break this separability by implicitly grouping individual Its via the shared state set up by the BeforeAll and torn down by the AfterAll.

Does this make sense? I'd love to hear your thoughts. FWIW I've avoided RSpec's before(:all) and after(:all) so I don't really miss them.

@modocache
Copy link
Author

That makes a lot of sense, thanks for the explanation!

I came across my specific use case when writing this. The post describes testing a HTTP handler. I believe creating the handler is fairly expensive, especially considering it opens a connection to a database, so I was hoping to only do it once. But I need a reference to the handler, so I can't easily move the initialization into a BeforeSuite.

That being said, I've only just started looking into web development with Go, so I'm certain there's a better way to accomplish what I'm doing. I was mainly curious as to why you'd leave out BeforeAll--now I know! Very enlightening, I'll keep it in mind next time I write a testing tool. 👍

@rnapier
Copy link

rnapier commented May 13, 2014

I know you got your answer, but just to add a little: Always try it before
you assume it'll be slow. It's often amazing just how fast it is, and if
you keep things separated correctly, you can run a lot of things in
parallel. Whenever possible, try to move the service local to your machine
(i.e. it's best to run a local database just for your tests rather than
talking to a server if you can set it up). You may even want to mock your
DB entirely. I have some test cases that kick off a small local server to
talk to. I'm able to run multiple instances of my test server by having
them listen on different ports. This keeps my test cases very independent.

If you must share a handle, you really should be able to initialize it in
BeforeSuite. Remember, package variables are shared throughout the package,
so you can create a global variable in one part of your test suite and use
it in another. I'd avoid this if possible, but if it is a stateless
connection, then it shouldn't actually cause trouble to share it. If it's
statefull, then you really shouldn't share it, even if you can figure out
how to.

I'll note that sometimes I'm torn about how many expectations to to put
into an It() just because every It() starts over from scratch. So, for
instance, it does feel crazy at times to run the whole test case once to
test "no error" and once to test the result code is good and again to test
that the returned data is good. But even when I break it down to that kind
of possibly crazy granularity, I'm amazed how fast it is anyway. So I've
gotten over it a bit, and focused on making the tests really clear and I'll
worry about making them fast if they're ever actually slow.

Good luck!

@onsi
Copy link
Owner

onsi commented May 13, 2014

Glad that was helpful @modocache -- and thanks for the sweet blog posts mentioning Ginkgo!

Also, thanks for chiming in @rnapier - I agree with your points. I also prefer smaller Its when possible. The primary exception being around integration-style suites that spin up several external processes and get them to play together -- these tend to be slow and breaking out separate Its when the assertions can be chained into one It becomes counterproductive.

@mml
Copy link

mml commented Jun 17, 2016

I know this is an ancient issue, but I'll mention another way this is an issue. In kubernetes, we have a rather large end-to-end test suite. There is a single suite for the entire project, and so the nested Describe/Context blocks often have very specific needs.

As this is an e2e setup, it's often the case that we need to create certain API objects and wait for them to stabilize in the running server. This is a high-latency operation. Currently we do this in BeforeEach blocks, which works but it strongly encourages test writers to build gigantic It() blocks because of the state teardown/construction. In effect, we have the same amount of test assertions "sharing state" as we would with BeforeAll, but the tests are large, harder to read, and they fail with very little granularity.

BeforeAll/AfterAll or equivalently nested suites would be a useful abstraction for this case.

@and-hom
Copy link

and-hom commented Oct 12, 2016

I need BeforeAll/AfterAll too. I created integration test for my application. It prepares environment, starts app and performs tests. So I'd like to test my app with different config files and different environment variables. And I have more then one test per each configuration.
Now I have to create a package per each test configuration and one more package for common test utils. It's a workaround and looks ugly.
It would be great to create own setUp/tearDown for Context

@onsi
Copy link
Owner

onsi commented Oct 15, 2016

@and-hom can you point me at a concrete or specific example?

PSA:

If you want BeforeAll or AfterAll you can always add a guard to a BeforeEach and AfterEach block to ensure it only runs once.

This will not work with paralellized tests or --randomizeAllSpecs. This is one reason why I do not intend to add BeforeAll or AfterAll.

@zeekay
Copy link

zeekay commented Oct 25, 2016

I think this would be a nice addition. It helps discourage massive It blocks, which are a natural response to BeforeEach blocks with high-latency setup work (as mentioned by @mml). As per @onsi's suggestion above we implemented our own BeforeAll helper like so:

func BeforeAll(fn func()) {
    first := true
    Before(func() {
        if first {
            fn()
            first = false
        }
    })
}

Which works well with our parallelized (and randomized) test setup.

This has been a boon in dealing with some particularly unreliable testing infrastructure (rapid iteration of It blocks causing test server to explode). Judicious use is of course advised, BeforeEach is what you want in most cases...

@b0o
Copy link

b0o commented Jan 3, 2017

@onsi

If you want BeforeAll or AfterAll you can always add a guard to a BeforeEach and AfterEach block to ensure it only runs once.

I can see how this makes BeforeAll possible, but how does it help with emulating AfterAll? Adding a guard to an AfterEach would just allow you to run it once after the first It, right?

I really need an AfterAll to reconstruct some high-cost objects.

I've been racking my brain trying to come up with various workarounds, but since the AfterEach will be the final thing to run within a Describe or Context, I don't know how to know that it's really the last one (or if it's even possible to know).

@akutz
Copy link

akutz commented Apr 19, 2017

Hi,

I also would like to see BeforeAll implemented for the same reason. Sometimes standing up an environment is expensive.

@glyoko
Copy link

glyoko commented May 19, 2017

+1

istalker2 pushed a commit to istalker2/virtlet that referenced this issue Aug 21, 2017
* Pure golang
* Framework that allows remote execution of commands and other
  operations on DinD k8s node (i.e. what `docker exec` does),
  k8s pods (like `kubectl exec`) and created VMs (like vmssh.sh) without
  executing external apps
* ginkgo test framework drop-in replacement that extends the framework
  with ability to have BeforeAll/AfterAll methods that do setup/teardown
  for current context as a workaround for
  onsi/ginkgo#70
* e2e suite is compiled into a standalone binary that has no system
  dependencies and can be run from outside of the cluster with
  virtlet deployed
* tests are performed in a temporary namespace that is deleted
  afterwards

Left to implement
* Further extend framework functionality
* Migrate rest of e2e tests from e2e.sh to new framework
* Completely delete e2e.sh (now both old and new e2e's are executed)
* Add CLI flag to skip tests that depend on DinD (i.e. that uses
  `docker exec` functionality to do something on the nodes) so that it
  would be possible to execute e2e against remote/bare-metal/etc k8s
  cluster

Also, noticeably decrease project build time for subsequent builds
by adding `-i` flag to `go build`
istalker2 pushed a commit to istalker2/virtlet that referenced this issue Aug 21, 2017
* Pure golang
* Framework that allows remote execution of commands and other
  operations on DinD k8s node (i.e. what `docker exec` does),
  k8s pods (like `kubectl exec`) and created VMs (like vmssh.sh) without
  executing external apps
* ginkgo test framework drop-in replacement that extends the framework
  with ability to have BeforeAll/AfterAll methods that do setup/teardown
  for current context as a workaround for
  onsi/ginkgo#70
* e2e suite is compiled into a standalone binary that has no system
  dependencies and can be run from outside of the cluster with
  virtlet deployed
* tests are performed in a temporary namespace that is deleted
  afterwards

Left to implement
* Further extend framework functionality
* Migrate rest of e2e tests from e2e.sh to new framework
* Completely delete e2e.sh (now both old and new e2e's are executed)
* Add CLI flag to skip tests that depend on DinD (i.e. that uses
  `docker exec` functionality to do something on the nodes) so that it
  would be possible to execute e2e against remote/bare-metal/etc k8s
  cluster

Also, noticeably decrease project build time for subsequent builds
by adding `-i` flag to `go build`
istalker2 pushed a commit to istalker2/virtlet that referenced this issue Aug 21, 2017
* Pure golang
* Framework that allows remote execution of commands and other
  operations on DinD k8s node (i.e. what `docker exec` does),
  k8s pods (like `kubectl exec`) and created VMs (like vmssh.sh) without
  executing external apps
* ginkgo test framework drop-in replacement that extends the framework
  with ability to have BeforeAll/AfterAll methods that do setup/teardown
  for current context as a workaround for
  onsi/ginkgo#70
* e2e suite is compiled into a standalone binary that has no system
  dependencies and can be run from outside of the cluster with
  virtlet deployed
* tests are performed in a temporary namespace that is deleted
  afterwards

Left to implement
* Further extend framework functionality
* Migrate rest of e2e tests from e2e.sh to new framework
* Completely delete e2e.sh (now both old and new e2e's are executed)
* Add CLI flag to skip tests that depend on DinD (i.e. that uses
  `docker exec` functionality to do something on the nodes) so that it
  would be possible to execute e2e against remote/bare-metal/etc k8s
  cluster

Also, noticeably decrease project build time for subsequent builds
by adding `-i` flag to `go build`
istalker2 pushed a commit to istalker2/virtlet that referenced this issue Aug 21, 2017
* Pure golang
* Framework that allows remote execution of commands and other
  operations on DinD k8s node (i.e. what `docker exec` does),
  k8s pods (like `kubectl exec`) and created VMs (like vmssh.sh) without
  executing external apps
* ginkgo test framework drop-in replacement that extends the framework
  with ability to have BeforeAll/AfterAll methods that do setup/teardown
  for current context as a workaround for
  onsi/ginkgo#70
* e2e suite is compiled into a standalone binary that has no system
  dependencies and can be run from outside of the cluster with
  virtlet deployed
* tests are performed in a temporary namespace that is deleted
  afterwards

Left to implement
* Further extend framework functionality
* Migrate rest of e2e tests from e2e.sh to new framework
* Completely delete e2e.sh (now both old and new e2e's are executed)
* Add CLI flag to skip tests that depend on DinD (i.e. that uses
  `docker exec` functionality to do something on the nodes) so that it
  would be possible to execute e2e against remote/bare-metal/etc k8s
  cluster

Also, noticeably decrease project build time for subsequent builds
by adding `-i` flag to `go build`
istalker2 pushed a commit to istalker2/virtlet that referenced this issue Aug 25, 2017
* Pure golang
* Framework that allows remote execution of commands and other
  operations on DinD k8s node (i.e. what `docker exec` does),
  k8s pods (like `kubectl exec`) and created VMs (like vmssh.sh) without
  executing external apps
* ginkgo test framework drop-in replacement that extends the framework
  with ability to have BeforeAll/AfterAll methods that do setup/teardown
  for current context as a workaround for
  onsi/ginkgo#70
* e2e suite is compiled into a standalone binary that has no system
  dependencies and can be run from outside of the cluster with
  virtlet deployed
* tests are performed in a temporary namespace that is deleted
  afterwards

Also, noticeably decrease project build time for subsequent builds
by adding `-i` flag to `go build`
istalker2 pushed a commit to istalker2/virtlet that referenced this issue Aug 26, 2017
* Pure golang
* Framework that allows remote execution of commands and other
  operations on DinD k8s node (i.e. what `docker exec` does),
  k8s pods (like `kubectl exec`) and created VMs (like vmssh.sh) without
  executing external apps
* ginkgo test framework drop-in replacement that extends the framework
  with ability to have BeforeAll/AfterAll methods that do setup/teardown
  for current context as a workaround for
  onsi/ginkgo#70
* e2e suite is compiled into a standalone binary that has no system
  dependencies and can be run from outside of the cluster with
  virtlet deployed
* tests are performed in a temporary namespace that is deleted
  afterwards

Also, noticeably decrease project build time for subsequent builds
by adding `-i` flag to `go build`
istalker2 pushed a commit to istalker2/virtlet that referenced this issue Aug 28, 2017
* Pure golang
* Framework that allows remote execution of commands and other
  operations on DinD k8s node (i.e. what `docker exec` does),
  k8s pods (like `kubectl exec`) and created VMs (like vmssh.sh) without
  executing external apps
* ginkgo test framework drop-in replacement that extends the framework
  with ability to have BeforeAll/AfterAll methods that do setup/teardown
  for current context as a workaround for
  onsi/ginkgo#70
* e2e suite is compiled into a standalone binary that has no system
  dependencies and can be run from outside of the cluster with
  virtlet deployed
* tests are performed in a temporary namespace that is deleted
  afterwards

Also, noticeably decrease project build time for subsequent builds
by adding `-i` flag to `go build`
istalker2 pushed a commit to istalker2/virtlet that referenced this issue Aug 28, 2017
* Pure golang
* Framework that allows remote execution of commands and other
  operations on DinD k8s node (i.e. what `docker exec` does),
  k8s pods (like `kubectl exec`) and created VMs (like vmssh.sh) without
  executing external apps
* ginkgo test framework drop-in replacement that extends the framework
  with ability to have BeforeAll/AfterAll methods that do setup/teardown
  for current context as a workaround for
  onsi/ginkgo#70
* e2e suite is compiled into a standalone binary that has no system
  dependencies and can be run from outside of the cluster with
  virtlet deployed
* tests are performed in a temporary namespace that is deleted
  afterwards

Also, noticeably decrease project build time for subsequent builds
by adding `-i` flag to `go build`
ivan4th pushed a commit to Mirantis/criproxy that referenced this issue Nov 18, 2017
* Pure golang
* Framework that allows remote execution of commands and other
  operations on DinD k8s node (i.e. what `docker exec` does),
  k8s pods (like `kubectl exec`) and created VMs (like vmssh.sh) without
  executing external apps
* ginkgo test framework drop-in replacement that extends the framework
  with ability to have BeforeAll/AfterAll methods that do setup/teardown
  for current context as a workaround for
  onsi/ginkgo#70
* e2e suite is compiled into a standalone binary that has no system
  dependencies and can be run from outside of the cluster with
  virtlet deployed
* tests are performed in a temporary namespace that is deleted
  afterwards

Also, noticeably decrease project build time for subsequent builds
by adding `-i` flag to `go build`
ivan4th pushed a commit to Mirantis/criproxy that referenced this issue Nov 18, 2017
* Pure golang
* Framework that allows remote execution of commands and other
  operations on DinD k8s node (i.e. what `docker exec` does),
  k8s pods (like `kubectl exec`) and created VMs (like vmssh.sh) without
  executing external apps
* ginkgo test framework drop-in replacement that extends the framework
  with ability to have BeforeAll/AfterAll methods that do setup/teardown
  for current context as a workaround for
  onsi/ginkgo#70
* e2e suite is compiled into a standalone binary that has no system
  dependencies and can be run from outside of the cluster with
  virtlet deployed
* tests are performed in a temporary namespace that is deleted
  afterwards

Also, noticeably decrease project build time for subsequent builds
by adding `-i` flag to `go build`
ivan4th pushed a commit to Mirantis/criproxy that referenced this issue Nov 18, 2017
* Pure golang
* Framework that allows remote execution of commands and other
  operations on DinD k8s node (i.e. what `docker exec` does),
  k8s pods (like `kubectl exec`) and created VMs (like vmssh.sh) without
  executing external apps
* ginkgo test framework drop-in replacement that extends the framework
  with ability to have BeforeAll/AfterAll methods that do setup/teardown
  for current context as a workaround for
  onsi/ginkgo#70
* e2e suite is compiled into a standalone binary that has no system
  dependencies and can be run from outside of the cluster with
  virtlet deployed
* tests are performed in a temporary namespace that is deleted
  afterwards

Also, noticeably decrease project build time for subsequent builds
by adding `-i` flag to `go build`
@tzvatot
Copy link

tzvatot commented Feb 18, 2019

I know this is an ancient issue, but I'll mention another way this is an issue. In kubernetes, we have a rather large end-to-end test suite. There is a single suite for the entire project, and so the nested Describe/Context blocks often have very specific needs.

As this is an e2e setup, it's often the case that we need to create certain API objects and wait for them to stabilize in the running server. This is a high-latency operation. Currently we do this in BeforeEach blocks, which works but it strongly encourages test writers to build gigantic It() blocks because of the state teardown/construction. In effect, we have the same amount of test assertions "sharing state" as we would with BeforeAll, but the tests are large, harder to read, and they fail with very little granularity.

BeforeAll/AfterAll or equivalently nested suites would be a useful abstraction for this case.

I'm facing the same issue: working with openshift (kubernetes based) I have a test suite devided to several contexts and specs. Some tests needs a setup before their execution. The setup takes a long time, but it's the same setup for all It in the context, which the outcome is a state which the test requires in order to run. Running the setup before each test cause the test duration to exceed the timeout. Besides it consumes a lot of redundant resources.
Having a beforeAll and afterAll would allow me to setup the state, pass that to each It as a context variable and tear it down on at the end of all of them.

@williammartin
Copy link
Collaborator

@tzvatot Thanks for your feedback! Is this code somewhere I can see?

@tzvatot
Copy link

tzvatot commented Feb 18, 2019

@tzvatot Thanks for your feedback! Is this code somewhere I can see?

Unfortunately no. But we might open it up sometime in the future.

@wookasz
Copy link

wookasz commented Apr 17, 2020

+1 on the BeforeAll and AfterAll. We have some integration tests which involve indexing to elasticsearch. It can take over a second for the document to be updated in ES in the test environment. We want to be able to trigger the document update and test several assertions. Multiple assertions in a single It are not ideal because it's unclear which assertion failed and when a single assertion fails, the remaining ones are not executed.

@arxeiss
Copy link

arxeiss commented Jul 31, 2020

Doesn't BeforeSuite() and AfterSuite() solving exactly this problem? http://onsi.github.io/ginkgo/#global-setup-and-teardown-beforesuite-and-aftersuite

Global Setup and Teardown: BeforeSuite and AfterSuite

Sometimes you want to run some set up code once before the entire test suite and some clean up code once after the entire test suite. For example, perhaps you need to spin up and tear down an external database.

Ginkgo provides BeforeSuite and AfterSuite to accomplish this. You typically define these at the top-level in the bootstrap file. For example, say you need to set up an external database:

@tzvatot
Copy link

tzvatot commented Aug 2, 2020

@arxeiss no, it does not solve the problem. As mentioned in the documentation, the BeforeSuite and AfterSuite are global.

For example, assume I have a single test suite called "regression". This test suite contains several test cases. Few of the tests share the same exact setup, which is costly both in time and resources. So instead of forcing each of those tests to do it's own setup, we like to run that setup once, to create some basic resources that will be used by all those tests, and once they finish, we can remove those resources.

Of course, you may argue that those should be in a separated Suite, but since we have several such "groups" of tests that should share the setup and teardown in the "regression" suite, it means that every real life suite will actually be a group of suites (which opens another question about missing BeforeEachSuite and AfterEachSuite).

@liuxh0
Copy link

liuxh0 commented Mar 12, 2021

Generally, it does make sense without BeforeAll and AfterAll.
However, while I was writing integration tests recently, I do need them to reduce calling external services, which are time-consuming.

-> Therefore, +1 for BeforeAll / AfterAll. Also would like to know the best practices for integration tests using Ginkgo.

@blgm
Copy link
Collaborator

blgm commented Mar 12, 2021

Ginkgo 2.0 (see #711) will hopefully add some additional controls to help with this.

@onsi onsi reopened this Sep 21, 2021
@onsi onsi added the v2 Issues that will be resolved by v2 label Sep 21, 2021
@onsi
Copy link
Owner

onsi commented Sep 21, 2021

Am happy to share that over 7 years later, the ver2 branch now includes support for Ordered contexts which can include BeforeAll and AfterAll.

@hamadise
Copy link

hamadise commented Oct 1, 2021

We do use Ginkgo to develop a framework to test applications of Openshift/Kubernetes and having BeforeAll is really sweet option. Otherwise, we're forced to do that ourselves (not in a clean way)
In Openshift, we do need to setup the whole application with all the sessions to different Pods/Nodes.
Then we do run different suites and differents tests. "It" blocks are fully separated and can run in any given order. We can add the whole logic of setting up the app and sessions inside beforeEach. But it takes a significant amount of time.
Reading the comments, people such as (@tzvatot @mml ) are also facing similar issue in k8s/openshift.
our code is open and anyone is welcome to check it and see how ginkgo is really useful https://github.com/test-network-function/test-network-function
We're waiting for official release of Ginkgo v2 :)

@onsi onsi closed this as completed Nov 16, 2022
@tzvatot
Copy link

tzvatot commented Nov 16, 2022

@onsi how can I find the PR for this? what version will include it?

@onsi
Copy link
Owner

onsi commented Nov 16, 2022

hey - this shipped in 2.0 and is documented here.

@tzvatot
Copy link

tzvatot commented Dec 20, 2022

@onsi it seems that the BeforeAll/AfterAll is strongly tight with Ordered context. This cause the following issue:
In case of using a DescribeTable with multiple entries, the first entry fails the rest of the entries, because it's Ordered. Removing the Ordered is not an option as it prevents using BeforeAll/AfterAll.
We need an ability to have BeforeAll/AfterAll, but still be able to have DescribeTable run through all of the entries, without skipping them as soon as the first fails.

@onsi
Copy link
Owner

onsi commented Dec 20, 2022

hey @tzvatot do you mind opening a new issue so we can discuss it there? i'd like to learn more about what you're doing in the table test to figure out what potential solutions for you are.

@tzvatot
Copy link

tzvatot commented Dec 20, 2022

hey @tzvatot do you mind opening a new issue so we can discuss it there? i'd like to learn more about what you're doing in the table test to figure out what potential solutions for you are.

#1103 submitted

@onsi
Copy link
Owner

onsi commented Jan 9, 2023

cross-posting here since this is the issue that folks thinking about BeforeAll/AfterAll usually land on:

2.7.0 introduces the ContinueOnFailure decorator which resolves #1103 and allows specs in ordered containers to continue running if an earlier spec fails.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
v2 Issues that will be resolved by v2
Projects
None yet
Development

No branches or pull requests