Spock performance problems - performance

I've some problems with performance with specifications implemented in Spock - I mean execution time in particular. After digging into the problem, I've noticed that it's somehow related with setting spec up - I don't mean setup() method in particular.
After this discovery, I added #Shared annotation to all the fields declared in the specification and it runs 2 times faster than before. Then, I thought, that performance problems may be related to ConcurrentHashMap or random* methods (from commons-lang3) but that wasn't the case.
In the end, in an act of desperation, I decorated all the fields in my specification in the following way:
class EntryFacadeSpec extends Specification {
static {
println(System.currentTimeMillis())
}
#Shared
def o = new Object()
static {
println(System.currentTimeMillis())
}
#Shared
private salesEntries = new InMemorySalesEntryRepository()
static {
println(System.currentTimeMillis())
}
#Shared
private purchaseEntries = new InMemoryPurchaseEntryRepository()
static {
println(System.currentTimeMillis())
}
...
What's interesting, no matter which field is declared as the first one it takes hundreds of milliseconds to initialize the field:
1542801494583
1542801495045
1542801495045
1542801495045
1542801495045
1542801495045
1542801495045
1542801495045
1542801495045
1542801495045
1542801495046
1542801495046
1542801495046
1542801495046
1542801495047
1542801495047
What's the problem? How to save this several hundred milliseconds?

TL;DR
Calling printlnin the first static block initializes about 30k+ objects related to Groovy Development Kit. It can take 50 ms at the minimum to finish, depending on horsepower of the laptop we run this test on.
The details
I couldn't reproduce the lag at the level of hundreds of milliseconds, but I was able to get a lag between 30 to 80 milliseconds. Let's start with the class I used in my local tests that reproduces your use case.
import spock.lang.Shared
import spock.lang.Specification
class EntryFacadeSpec extends Specification {
static {
println("${System.currentTimeMillis()} - start")
}
#Shared
def o = new Object()
static {
println("${System.currentTimeMillis()} - object")
}
#Shared
private salesEntries = new InMemorySalesEntryRepository()
static {
println("${System.currentTimeMillis()} - sales")
}
#Shared
private purchaseEntries = new InMemoryPurchaseEntryRepository()
static {
println("${System.currentTimeMillis()} - purchase")
}
def "test 1"() {
setup:
System.out.println(String.format('%d - test 1', System.currentTimeMillis()))
when:
def a = 1
then:
a == 1
}
def "test 2"() {
setup:
System.out.println(String.format('%d - test 2', System.currentTimeMillis()))
when:
def a = 2
then:
a == 2
}
static class InMemorySalesEntryRepository {}
static class InMemoryPurchaseEntryRepository {}
}
Now, when I run it I see something like this in the console.
1542819186960 - start
1542819187019 - object
1542819187019 - sales
1542819187019 - purchase
1542819187035 - test 1
1542819187058 - test 2
We can see 59 milliseconds lag between the two first static blocks. It doesn't matter what is between these two blocks, because Groovy compiler merges all these 4 static blocks to a single static block that looks like this in plain Java:
static {
$getCallSiteArray()[0].callStatic(EntryFacadeSpec.class, new GStringImpl(new Object[]{$getCallSiteArray()[1].call(System.class)}, new String[]{"", " - start"}));
$getCallSiteArray()[2].callStatic(EntryFacadeSpec.class, new GStringImpl(new Object[]{$getCallSiteArray()[3].call(System.class)}, new String[]{"", " - object"}));
$getCallSiteArray()[4].callStatic(EntryFacadeSpec.class, new GStringImpl(new Object[]{$getCallSiteArray()[5].call(System.class)}, new String[]{"", " - sales"}));
$getCallSiteArray()[6].callStatic(EntryFacadeSpec.class, new GStringImpl(new Object[]{$getCallSiteArray()[7].call(System.class)}, new String[]{"", " - purchase"}));
}
So this 59 milliseconds lag happens between two first lines. Let's put a breakpoint in the first line and run a debugger.
Let's step over this line to the next line and let's see what happens:
We can see that invoking Groovy's println("${System.currentTimeMillis()} - start") caused creating more than 30k objects in the JVM. Now, let's step over the second line to the 3rd one to see what happens:
Only a few more objects got created.
This example shows that adding
static {
println(System.currentTimeMillis())
}
adds accidental complexity to the test setup and it does not show there is a lag between initialization of two class methods, but it creates this lag. However, the cost of initializing all Groovy related objects is something we can't completely avoid and it has to be paid somewhere. For instance, if we simplify the test to something like this:
import spock.lang.Specification
class EntryFacadeSpec extends Specification {
def "test 1"() {
setup:
println "asd ${System.currentTimeMillis()}"
println "asd ${System.currentTimeMillis()}"
when:
def a = 1
then:
a == 1
}
def "test 2"() {
setup:
System.out.println(String.format('%d - test 2', System.currentTimeMillis()))
when:
def a = 2
then:
a == 2
}
}
and we put a breakpoint in the first println statement and step over to the next one, we will see something like this:
It still creates a few thousands of objects, but it is much less than in the first example because most of the objects we saw in the first example were already created before Spock executed the first method.
Overclocking Spock test performance
One of the first things we can do is to use static compilation. In case of my simple test it reduced execution time from 300 ms (non static compilation) to 227 ms approximately. Also the number of objects that have to be initialized is significantly reduced. If I run the same debugger scenario as the last one shown above with #CompileStatic added, I will get something like this:
It is still pretty significant, but we see that the number of objects initialized to invoke println method was dropped.
And the last thing worth mentioning. When we use static compilation and we want to avoid calling Groovy methods in the class static block to print some output we can use a combination of:
System.out.println(String.format("...", args))
because Groovy executes exactly this. On the other hand, following code in Groovy:
System.out.printf("...", args)
may look similar to the previous one, but it gets compiled to something like this (with static compilation enabled):
DefaultGroovyMethods.printf(System.out, "...", args)
The second case will be much slower when used in the class static block, because at this point Groovy jar is not yet loaded and the classloader has to resolve DefaultGroovyMethods class from the JAR file. When Spock executes test method it doesn't make much difference if you use System.out.println or DefaultGroovyMethods.printf, because Groovy classes are already loaded.
That is why if we rewrite your initial example to something like this:
import groovy.transform.CompileStatic
import spock.lang.Shared
import spock.lang.Specification
#CompileStatic
class EntryFacadeSpec extends Specification {
static {
System.out.println(String.format('%d - start', System.currentTimeMillis()))
}
#Shared
def o = new Object()
static {
System.out.println(String.format('%d - object', System.currentTimeMillis()))
}
#Shared
private salesEntries = new InMemorySalesEntryRepository()
static {
System.out.println(String.format('%d - sales', System.currentTimeMillis()))
}
#Shared
private purchaseEntries = new InMemoryPurchaseEntryRepository()
static {
System.out.println(String.format('%d - purchase', System.currentTimeMillis()))
}
def "test 1"() {
setup:
System.out.println(String.format('%d - test 1', System.currentTimeMillis()))
when:
def a = 1
then:
a == 1
}
def "test 2"() {
setup:
System.out.println(String.format('%d - test 2', System.currentTimeMillis()))
when:
def a = 2
then:
a == 2
}
static class InMemorySalesEntryRepository {}
static class InMemoryPurchaseEntryRepository {}
}
we will get following console output:
1542821438552 - start
1542821438552 - object
1542821438552 - sales
1542821438552 - purchase
1542821438774 - test 1
1542821438786 - test 2
But what is more important, it doesn't log field initialization time, because Groovy compiles these 4 blocks to a single one like this:
static {
System.out.println(String.format("%d - start", System.currentTimeMillis()));
Object var10000 = null;
System.out.println(String.format("%d - object", System.currentTimeMillis()));
var10000 = null;
System.out.println(String.format("%d - sales", System.currentTimeMillis()));
var10000 = null;
System.out.println(String.format("%d - purchase", System.currentTimeMillis()));
var10000 = null;
}
There is no lag between the 1st and 2nd call, because there is no need to load Groovy classes at this point.

Related

Laravel 8 Testing - using RefreshDatabase but table not found

I'm trying to refactor a class and having problems testing it when I place certain code in the __constructor method and it throws an error that table not found within the test but works outside of tests.
I know this means that in the testing environment the table has yet to be created and although I'm using RefreshDatabase within the test it appears that at the point the class I'm testing initialises and attempts to access the database it's not ready. So I'm either doing something in the constructor I shouldn't or I'm missing something in my test structure.
Here's the basics of the class I'm tryting to test:
class PlayerRounds
{
use EclecticPresenter;
private RoundRepository $roundRepository;
private CourseRepository $courseRepository;
private $courseHoles;
public function __construct(RoundRepository $roundRepository, CourseRepository $courseRepository)
{
$this->roundRepository = $roundRepository;
$this->courseRepository = $courseRepository;
$this->init();
}
private function init()
{
$this->courseHoles = $this->courseRepository->all();
}
/**
* generates eclecic rounds for each league the player is in
* #param Player $player
*/
public function getAllEclecticRounds(Player $player)
{
$allEclecticRounds = collect();
$leagues = $player->league()->where('league_type', 'eclectic')->get();
$leagues->each(function ($league) use ($player, $allEclecticRounds) {
$newRound = $this->getPlayerEclecticRound($player, $league);
$allEclecticRounds->put($league->id, $newRound);
});
return $allEclecticRounds;
}
The test fails at the init() method. The fetch $this->courseHoles = $this->courseRepository->all(); the the test fails with a table not found error if it's within the constructor, It works if I place this piece of code within each method that needs it but means I call it often rather than once.
Here's my test:
class PlayerRoundsTest extends TestCase
{
use RefreshDatabase;
use EclecticTestHelper;
use WithFaker;
private $playerRounds;
protected function setUp(): void
{
parent::setUp();
$this->seed(CourseTableSeeder::class);
$this->playerRounds = app()->make(PlayerRounds::class);
}
/**
* #test
* #covers PlayerRounds::getAllEclecticRounds
* #description:
*/
public function it_returns_an_eclectic_round_for_all_leagues()
{
$player = Player::factory()->has(League::factory()->count(3))->create();
foreach ($player->league()->get() as $league) {
for ($x = 0; $x <= 3; $x++) {
$this->createScores($league, $player);
}
}
$result = $this->playerRounds->getAllEclecticRounds($player);
$this->assertCount(3, $result);
$result->each(function($collection) {
$this->assertCount(1, $collection);
});
Are there any ideas how I can initiate the class correctly and get the test set up correct and ensure the database is ready for the test. I assumed using RefreshDatabase was the correct approach and I had things in the correct order.
Thank you
**update
If I change the constructor to this:
public function __construct(RoundRepository $roundRepository, CourseRepository $courseRepository)
{
$this->roundRepository = $roundRepository;
$this->courseRepository = $courseRepository;
}
and then place the code that calls on the database to the method used in the test back to this:
public function getPlayerEclecticRound(Player $player, League $league, $maxDate = null)
{
// FIXME: Initiate at start in constructor but fails in tests
$this->courseHoles = $this->courseRepository->all();
//rest of code removed for brevity
}
This then passes the test.
This class needs the data in $this->courseHoles for a number of methods to work so I'm aiming to just call this once at initialization rather than every time I access the method as it is now but can' get it to work in a testing environment.
note I'm using a mysql database on the server but a sqllite memory database in testing
###update
Ok, after a bit of playing around the error is being caused by the loading of a custom artisan command I created. That command class has a dependancy of another class which in turn calls on the class I'm tresting.
I removed the command from Kernel.php as follows:
protected $commands = [
Inspire::class,
FixtureReminder::class,
SmsFixtureReminder::class,
UpdateMigrationTable::class,
// EclecticUpdate::class,
// MatchplayUpdate::class,
CleanTemporaryFiles::class,
AuthPermissionCommand::class
];
So - am I right in assuming for test purposes this is going to be impossible to isolate without changing this each time? This all relates to dependencies and the order in which CreateApplication works but I don't know enough to work around this.

list of locales passed as a query param to spring restcontroller showing irregular behaviour while testing

I have a spring restcontroller (written in kotlin and running spring boot 2.1.7, using spring-mockk as mock framework for testing) which takes a list of locales as parameter. In my test, I'm randomly generating a list of locale and verifying whether the controller is calling the service using the same list of locales. This test is failing 2/3 times out of every 10 times. I checked the logs and the list of locales are the exactly same. what am I doing wrong?
The code for my controller:
#RequestMapping("/api/v1/locale")
#RestController
class LocaleController (private val service: LocaleService){
#GetMapping
fun simpleApi(#RequestParam locales: List<Locale>) = service.getLocale(locales)
}
my dummy service:
#Service
class LocaleService {
fun getLocale(list: List<Locale>) = "1"
}
my test code:
#WebMvcTest(controllers = [LocaleController::class])
class LocaleControllerTest {
#Autowired
lateinit var mvc : MockMvc
#MockkBean
lateinit var service: LocaleService
#RepeatedTest(10)
fun `test locale api`(){
every { service.getLocale(any()) } returns "1"
val list = randomList{ locale() }
get("/api/v1/locale")
.param("locales", *list.map { it.toString() }.toTypedArray())
.let { mvc.perform(it) }
.andExpect (status().isOk)
verify {
service.getLocale(list)
}
}
private fun locale(): Locale {
val availableLocales = getAvailableLocales()
return availableLocales[(0..1000).random() % availableLocales.size]
}
private fun <T> randomList(f: (Int) -> T) = List(10, f)
}
This test is failing 2/3 times out of every 10 times any time I run. The test log:
java.lang.AssertionError: Verification failed: call 1 of 1: LocaleService(org.dripto.springkotlinplayground.LocaleService#0 bean#1).getLocale(eq([sr_BA, ja_JP_JP_#u-ca-japanese, et, es_SV, sq, ar, fr_CH, tr, ca_ES, ar_QA]))). Only one matching call to LocaleService(org.dripto.springkotlinplayground.LocaleService#0 bean#1)/getLocale(List) happened, but arguments are not matching:
[0]: argument: [sr_BA, ja_JP_JP_#u-ca-japanese, et, es_SV, sq, ar, fr_CH, tr, ca_ES, ar_QA], matcher: eq([sr_BA, ja_JP_JP_#u-ca-japanese, et, es_SV, sq, ar, fr_CH, tr, ca_ES, ar_QA]), result: -
Stack trace:
io.mockk.impl.InternalPlatform.captureStackTrace (InternalPlatform.kt:121)
io.mockk.impl.stub.MockKStub.handleInvocation (MockKStub.kt:247)
io.mockk.impl.instantiation.JvmMockFactoryHelper$mockHandler$1.invocation
The problem is that there are locales with the same toString value. You can see this if you add the following statement in both the controller, as first statement, and in the test, directly after creating the list
locales.forEach {
println("$it ${it.displayCountry} ${it.displayLanguage} ${it.displayName} ${it.displayScript} ${it.displayVariant} ${it.isO3Country} ${it.isO3Language} ${it.variant}")
}
I did this and the failing test showed me this:
sr_BA_#Latn Bosnia and Herzegovina Serbian Serbian (Latin,Bosnia and Herzegovina) Latin BIH srp
for the one and
sr_BA_#Latn Bosnia and Herzegovina Serbian Serbian (Bosnia and Herzegovina,#Latn) #Latn BIH srp #Latn
for the other. These are seen as different locales, but both are "sr_BA_Latn"

groovy/SoapUi Call a static function from another script

I am trying to write a groovy script which will contain functions that are common to the SoapUI test Suite. Specifically I want to write a script that will contain all the logs that are output from the test suite.
GroovyScript1 will call a function in the GroovyScripts.groovy file. All is present in a SoapUI test suite.
I have not found any helpful advice on how to perform this task.
To specify again, I want to call a function contained in another Groovy Script.
Yes You can do this by following steps,
In your "GroovyScripts.groovy" file add below code,
class GLF
{
def log
def context
def testRunner
def GLF(logIn, contextIn, testRunnerIn)
{
this.log = logIn
this.context = contextIn
this.testRunner = testRunnerIn
}
//Till abobe line you must keep same code except class name
public String returnVal()
{
return 'Himanshu'
}
}
context.setProperty("Rt", new GLF(log, context, testRunner))
============================ END GroovyScripts.groovy ==========
Now in your "GroovyScript1" file you should use below code,
lib = testRunner.testCase.testSuite.project.testSuites["GroovyLibraryFunction"].testCases["TestCase 1"].testSteps["EndpointVerification"]
lib.run(testRunner, context)
def RT = context.Rt
def PT = RT.returnVal()
log.info PT
This way you can achive your target.

how to selectively set a property using DEPENDENCY INJECTION in a grails service for unit testing

EDIT: Please let me be clear, I'm asking how to do this in Grails using Spring Dependency Injection, and NOT Grails' metaclass functionality or new().
I have a grails service that is for analyzing log files. Inside the service I use the current time for lots of things. For unit testing I have several example log files that I parse with this service. These have times in them obviously.
I want my service, DURING UNIT TESTING to think that the current time is no more than a few hours after the last logging statement in my example log files.
So, I'm willing to this:
class MyService {
def currentDate = { -> new Date() }
def doSomeStuff() {
// need to know when is "right now"
Date now = currentDate()
}
}
So, what I want to be able to do is have currentDate injected or set to be some other HARDCODED time, like
currentDate = { -> new Date(1308619647140) }
Is there not a way to do this with some mockWhatever method inside my unit test? This kind of stuff was super easy with Google Guice, but I have no idea how to do it in Spring.
It's pretty frustrating that when I Google "grails dependency injection" all I find are examples of
class SomeController {
// wow look how amazing this is, it's injected automatically!!
// isn't spring incredible OMG!
def myService
}
It feels like all that's showing me is that I don't have to type new ...()
Where do I tell it that when environment equals test, then do this:
currentDate = { -> new Date(1308619647140) }
Am I just stuck setting this property manually in my test??
I would prefer not to have to create a "timeService" because this seems silly considering I just want 1 tiny change.
Groovy is a dynamic language, and as such it allows you to do almost what you're asking for:
class MyServiceTests extends GrailsUnitTestCase {
def testDoSomeStuff() {
def service = new MyService()
service.currentDate = { -> new Date(1308619647140) }
// assert something on service.doSomeStuff()
}
}
Keep in mind this only modifies the service instance, not the class. If you need to modify the class you'll need to work with the metaClass. Take a look at this post by mrhaki.
Another option would be to make the current date a parameter to doSomeStuff(). That way you wouldn't need to modify your service instance.
Thanks for the help guys. The best solution I could come up with for using Spring DI in this case was to do the following in
resources.groovy
These are the two solutions I found:
1: If I want the timeNowService to be swapped for testing purposes everywhere:
import grails.util.GrailsUtil
// Place your Spring DSL code here
beans = {
if (GrailsUtil.environment == 'test') {
println ">>> test env"
timeNowService(TimeNowMockService)
} else {
println ">>> not test env"
timeNowService(TimeNowService)
}
}
2: I could do this if I only want this change to apply to this particular service:
import grails.util.GrailsUtil
// Place your Spring DSL code here
beans = {
if (GrailsUtil.environment == 'test') {
println ">>> test env"
time1(TimeNowMockService)
} else {
println ">>> not test env"
time1(TimeNowService)
}
myService(MyService) {
diTest = 'hello 2'
timeNowService = ref('time1')
}
}
In either case I would use the service by calling
timeNowService.now().
The one strange, and very frustrating thing to me was that I could not do this:
import grails.util.GrailsUtil
// Place your Spring DSL code here
beans = {
if (GrailsUtil.environment == 'test') {
println ">>> test env"
myService(MyService) {
timeNow = { -> new Date(1308486447140) }
}
} else {
println ">>> not test env"
myService(MyService) {
timeNow = { -> new Date() }
}
}
}
In fact, when I tried that I also had a dummy value in there, like dummy = 'hello 2' and then a default value of dummy = 'hello' in the myService class itself. And when I did this 3rd example with the dummy value set in there as well, it silently failed to set, apparently b/c timeNow blew something up in private.
I would be interested to know if anyone could explain why this fails.
Thanks for the help guys and sorry to be impatient...
Since Groovy is dynamic, you could just take away your currentDate() method from your service and replace it by one that suits your need. You can do this at runtime during the setup of your test.
Prior to having an instance of MyService instantiated, have the following code executed:
MyService.metaClass.currentDate << {-> new Date(1308619647140) }
This way, you can have a consistent behavior across all your tests.
However, if you prefer, you can override the instance method by a closure that does the same trick.
Let me know how it goes.
Vincent Giguère

Identifying slow-running tests

In ruby's test/unit, the software indicates how long it takes for the tests to run, and the series of passes, errors and fails act like a pseudo-progress bar.
Apart from using code profiling tools or running tests individually, is there an easy way of telling which test methods are fast and which ones are slow?
When I need to do this in a large test suite, I override Test::Unit::TestCase setup and teardown. It doesn't give precise measurements, but it can help assess relative speed.
module Test
module Unit
def setup
#start_time = Time.now
end
def teardown
puts "#{#method_name}: #{Time.now - #start_time}s"
end
end
end
According to Sarah's answer, I would prefer another solution:
Setup like Sarah wrote, but the Teardown should add the test name and the execution time in a list.
So you can evaluate this list, for sorting or whatever. I don't know Ruby, so I don't know if it would work.
Here is some Java code for JUnit to explain my thoughts...
public class ExecutionTimeTest {
public static ArrayList<Double> executionTimes;
public double start;
#BeforeClass
public static void initializeList() {
executionTimes = new ArrayList<Double>();
}
#AfterClass
public static void printExecutionTimes() {
int i = 1;
for (Double time : executionTimes) {
System.out.println("Test " + (i++) + ": " + time);
}
}
#Before
public void startExecutionTime() {
start = System.currentTimeMillis();
}
#After
public void calculateExecutionTime() {
executionTimes.add(System.currentTimeMillis() - start);
}
}
If you're using the test-unit gem, running the tests in verbose mode will give you information on how long each test took:
ruby test/test_unit.rb --verbose
Loaded suite test/test_unit
Started
ChaserTestCase:
test_handle_funny_characters_in_class_method_names: .: (0.000645)
test_handle_funny_characters_in_instance_method_names:.: (0.000523)
test_modify_and_unmodify_class_method: .: (0.000534)
...
Finished in 0.019894 seconds.
MiniTest will also have benchmarking.

Resources