@SetupTestCase before each test case?

The annotations @SetupTestCase and @TearDownTestCase exist in a Test Suite/Test Listener, but is there a way to extend them to each test case as well?

Just to be clear, the use case for this would be for data creation for each test case, as well as data cleanup after a test is run. This setup is specific to each individual test case, and would not belong in a test suite.

example:

@SetupTestCase
def setupTestCase() {
//data setup
}

// run the test here

@TearDownTestCase
def tearDownTestCase() {
//data destruction
}

You want

@BeforeTestCase

@AfterTestCase

See …

1 Like

So if I have 300 tests, I need to setup 300 test listeners, and then link each test listener back to the test case?

@arild.andreassen

Yes, as you mentioned the logic is specific to each test case, so I think that’s exactly what you need to do.

1 Like

nope. you have to set up only two listeners, properly scoped (in fact one)

class Listener_dataSetup {

@BeforeTestCase
def beforeTC(TestCaseContext tcContext) {
  String tcId = tcContext.testCaseId

  //if or switch
  if(tcId == "my_test_case" {
    // setup data for my_test_case
  }
}
}

You could of course define a custom keyword and pass the tcId in to it. If you want to be super-groovy-smart, you could compute the keyword method name from the tcId and call it directly (that is, without if/switch statements).

So, strictly speaking, you don’t need to write 300 listeners, you need to handle them.

1 Like

that’s why you have hooks in the listener (the @ ones)

Yeah, I got it to work. So there is no way to build the before/after setup directly into the test?
I can see how I can handle all the before/after in a single test listener, but it doesn’t scale very well…
If the number of test cases increases, then the size of the test listener class will grow as well.

Just by the 300 test case example, each before/after would on average be maybe 10 lines of code. so for all the test cases, the test listener would have ~6000 lines of code

@BeforeTestCase
def beforeTC(TestCaseContext tcContext) {
  String tcId = tcContext.testCaseId

  //if or switch
  if(tcId == "my_test_case" {
    // setup data for my_test_case
  }

  if(tcId == "my_test_case_1" {
    // setup data for my_test_case_1
  }
.
.
.

  if(tcId == "my_test_case_n" {
    // setup data for my_test_case_n
  }
}

This answer is now superseded by my next answer. I will remove this answer at some point.


Correct. But…

I mentioned you could do something “super-groovy-smart”. That scales better, in my view.

Define one class (custom keyword in Katalon-speak). Add a method for each tcId. Something like:

public class TCHandlers {

  static void tcHandler_my_test_case() {

  }
  static void tcHandler_my_test_case2() {

  }
}

In your listener…

import static package_name.TCHandlers.*

@BeforeTestCase
def beforeTC(TestCaseContext tcContext) {
  String tcId = tcContext.testCaseId

  "tcHandler_" + tcId()  
}

I haven’t tested this but in principle it should work. You may need to instantiate the class and call TCHandlers."tcHandler_"+tcId()

The point here is, you either need to do the switching in a switch or an if or by declaring WKNs (well known names) so you can call them.

Looking at this again…

You could import TCHandlers into the Test Case and call the setup code from there. That way you don’t need…

  1. To compute the method name - you already know it.

  2. The listener.

Like that better?

One of the benefits of having the setup done in the test, is so it’s easy to see exactly what the test is doing in the before/after.

If it is all defined in the test listener area, it kind of feel a bit like magic for every test, and you would have to do some detective work to figure out what each specific test would do before launched. (login function and other generic methods are perfect for that).

Importing the TCHandlers is a better option, as you can quickly see what each test case is doing, while in the test. There is no magic happening.

You would still end up with a giant TCHandler class though (but you could also break this down further into subclasses under the TCHandler class)

I agree. Hence my stepping back and reviewing “how did we get here?”

Agreed 100%. But something somewhere needs to effect this construct. I think my latter approach is best.

But, if a test fail, it would then stop execution, and it would never get to the aftertestcase teardown, and any data you had created as part of the test would remain.

Good point.

I think we’re back to the listener.

Unless you handle all passes/fails yourself inside a try/catch. My tests do that.

this is how hooks are actualy working.
you declare them in a single (or many) listener(s), with the cost that at the runtime they are registered and compiled for any scoped instance.
for memory/runtime optimization with such large scenarios, you have to seriously consider custom hooks/threaded programing