(vía https://youtube.com/watch?v=DxE-FQlF4L8&feature=share)

seen from Malaysia
seen from China
seen from China
seen from United States

seen from Australia
seen from Morocco

seen from United States
seen from China
seen from Netherlands

seen from China
seen from United Kingdom

seen from China
seen from China

seen from United States
seen from Singapore
seen from Singapore

seen from United States

seen from Netherlands
seen from China
seen from China
(vía https://youtube.com/watch?v=DxE-FQlF4L8&feature=share)

Anya is live and ready to show you everything. Watch her strip, dance, and perform exclusive shows just for you. Interact in real-time and make your fantasies come true.
Free to watch • No registration required • HD streaming
Test pollution (part 1)
It’s been quite a while since I’ve blogged, but while my integration-test suite runs, I found time to share this.
I am on a rather large project, where I'm hired to migrate to Grails 3 (among other things). Here I have seen several things in integration tests that can potentially go wrong and lead to Test pollution. This is sometime seen as randomly failing tests and could happen if test-execution order changes, exposing the pollution. One of the issues could be mocking an injected service metaClass because the test requires a specific return value, and this was the only way to make it happen.
An example could be:
A service:
class TestService { AnotherService anotherService String myProperty String myMethod() { return "My Method" } }
and the test:
class ChangeMetaClassSpec extends Specification { def 'changing the meta class on an instance'() { given: 'a test instance' TestService sut = new TestService(myProperty: 'My Property') expect: 'methods and properties returns expected values' sut.myMethod() == 'My Method' sut.myProperty == 'My Property' when: 'mocking on the instance'' sut.metaClass { myProperty = 'Mocked Property' myMethod = { -> "Mocked Method" } } then: 'meta class values should be returned instead sut.myMethod() == 'Mocked Method' sut.myProperty == 'Mocked Property' } }
In it self not dangerous, when running it as a unit test, but consider this test:
class ChangeServiceMetaClassSpec extends Specification { // This would be like an injected service in an integration test, // as it is shared between invocations of the test. @Shared TestService testService = new TestService(myProperty: 'My Property') def 'changing the meta class on an instance'() { expect: 'methods and properties returns expected values' testService.myMethod() == 'My Method' testService.myProperty == 'My Property' when: 'mocking in a bad way' testService.metaClass { myProperty = 'Mocked Property' myMethod = { -> "Mocked Method" } } then: 'meta class values should be returned instead testService.myMethod() == 'Mocked Method' testService.myProperty == 'Mocked Property' } def 'using the instance after it was mocked'() { expect: 'methods and properties returns expected values' testService.myMethod() == 'My Method' testService.myProperty == 'My Property' } }
So while this looks like the previous test, the big culprit here is mocking the injected service instance (in this case a @Shared instance). This immediately shows when running the second test
This would fail, because the metaClass changes are still there, because changes took place on the shared instance. If metaClass changes were done on the class it self:
when: 'mocking in a better way' TestService.metaClass { myProperty = 'Mocked Property' myMethod = { -> "Mocked Method" } }
and we use Spock's @ConfineMetaClassChanges([TestService]) on the test:
@ConfineMetaClassChanges([TestService]) class ChangeServiceMetaClassSpec extends Specification { .. }
Then one would think that it should work, but it does not (at least not when running it with the @Shared option)
So I came up with a small helper, that solves the problem:
import org.junit.After import org.junit.AfterClass import org.slf4j.LoggerFactory trait MockMetaClassHelper { private Map<object> originalMetaClasses = [:] private log = LoggerFactory.getLogger(this.getClass().name) boolean postponeMetaClassCleanup = false /** * Replace an instance's metaClass with a new and save reference to the original. * A closure can be specified to make changes on the new metaClass. * @param instance * @param modifications * @return */ MetaClass mockMetaClass(Object instance, Closure modifications = null) { if (originalMetaClasses.containsKey(instance) || instance.metaClass instanceof ExpandoMetaClass) { log.info("MetaClass for ${instance.getClass().name} was already mocked, reusing metaClass") return instance.metaClass } originalMetaClasses.put(instance, instance.metaClass) MetaClass temporaryMetaClass = new ExpandoMetaClass(instance.getClass(), false, true) temporaryMetaClass.initialize() instance.metaClass = temporaryMetaClass if (modifications) { instance.metaClass(modifications) } log.debug "Replaced metaClass for ${instance.getClass().name}" return instance.metaClass } /** * Restores metaClass for an instance, if it was changed * @param instance */ void restoreMetaClass(Object instance) { MetaClass originalMetaClass = originalMetaClasses.remove(instance) if (originalMetaClass) { internalRestoreMetaClass(instance, originalMetaClass) } } /** * Automatically restores all metaClass changes after a test finishes (cleanup) */ @After void cleanupMetaClasses() { if (!postponeMetaClassCleanup) { originalMetaClasses.each { instance, originalMetaClass -> internalRestoreMetaClass(instance, originalMetaClass) } originalMetaClasses.clear() } } /** * Automatically restores all metaClass changes after all tests finishes (cleanupSpec) */ @AfterClass void cleanupSpecMetaClasses() { if (postponeMetaClassCleanup) { originalMetaClasses.each { instance, originalMetaClass -> internalRestoreMetaClass(instance, originalMetaClass) } originalMetaClasses.clear() } } private internalRestoreMetaClass(Object instance, MetaClass metaClass) { log.debug "Restored metaClass for ${instance.getClass().name}" instance.metaClass = metaClass } }
This will save the original metaClass and attach a new ExpandoMetaClass which we can work on, and finally it will automatically call cleanupMetaClasses restoring the objects initial metaClass
So basically we register our changes on the metaClass like this:
class ChangeServiceMetaClassSpec extends Specification implements MockMetaClassHelper { ---- def 'changing the meta class on an instance'() { given: .... when: "metaClass is mocked" mockMetaClass(sut) { myProperty = 'Mocked Property' myMethod = { -> "Mocked Method"} } then: ....
and when the test case has completed, it the original metaClass is restored.
the mockMetaClass returns the ExpandoMetaClass and it possible to to either modifications to it, or directly on your class instances metaClass knowing that when the test completes, the original metaClass is restored.
I hope this is helpful and will stop your tests from polluting each other.
Next blog post will be about a similar issue with replacing services with mocks during integration-tests in Grails and of course a solution too.
Stay Groovy!