Does Spock have Test Event Listeners - java

Does spock has any Test event listener like how TestNg has ITestListener. ?
So that I can have access, when the test cases failed etc.

Spock does have listeners. Unfortunately the official documentation, which is otherwise excellent, has "TODO" under Writing Custom Extensions: http://spockframework.github.io/spock/docs/1.0/extensions.html.
Update: The official docs have been updated to include helpful information about custom extensions: http://spockframework.org/spock/docs/1.1/extensions.html. See those for more details.
There are two ways: Annotation-based and Global.
Annotation-based
Three pieces here: the annotation, the extension, and the listener.
The annotation:
import java.lang.annotation.*
import org.spockframework.runtime.extension.ExtensionAnnotation
#Retention(RetentionPolicy.RUNTIME)
#Target([ElementType.TYPE, ElementType.METHOD])
#ExtensionAnnotation(ListenForErrorsExtension)
#interface ListenForErrors {}
The extension (Updated):
import org.spockframework.runtime.extension.AbstractAnnotationDrivenExtension
import org.spockframework.runtime.model.SpecInfo
class ListenForErrorsExtension extends AbstractAnnotationDrivenExtension<ListenForErrors> {
void visitSpec(SpecInfo spec) {
spec.addListener(new ListenForErrorsListener())
}
#Override
void visitSpecAnnotation(ListenForErrors annotation, SpecInfo spec){
println "do whatever you need here if you do. This method will throw an error unless you override it"
}
}
The listener:
import org.spockframework.runtime.AbstractRunListener
import org.spockframework.runtime.model.ErrorInfo
class ListenForErrorsListener extends AbstractRunListener {
void error(ErrorInfo error) {
println "Test failed: ${error.method.name}"
// Do other handling here
}
}
You can then use your new annotation on a Spec class or method:
#ListenForErrors
class MySpec extends Specification {
...
}
Global
This also has three pieces: the extension, the listener, and the registration.
class ListenForErrorsExtension implements IGlobalExtension {
void visitSpec(SpecInfo specInfo) {
specInfo.addListener(new ListenForErrorsListener())
}
}
You can use the same ListenForErrorsListener class as above.
To register the extension, create a file named org.spockframework.runtime.extension.IGlobalExtension in the META-INF/services directory. If using Gradle/Maven, this will be under src/test/resources. This file should contain only the fully qualified class name of your global extension, for example:
com.example.tests.ListenForErrorsExtension
References
For examples, see the Spock built-in extensions here:
https://github.com/spockframework/spock/tree/groovy-1.8/spock-core/src/main/java/spock/lang
https://github.com/spockframework/spock/tree/groovy-1.8/spock-core/src/main/java/org/spockframework/runtime/extension/builtin

Spock has interaction listening via Mock:
def "should send messages to all subscribers"() {
given:
def subscriber = Mock(Subscriber)
when:
publisher.send("hello")
then:
1 * subscriber.receive("hello")
}
See the interaction based testing in the docs

Related

JUnit: is it possible to create a Test Suite that executes all test of classes that share a naming convention?

I am aware that I can make a TestSuite enumerating all the classes that I want, for example:
#RunWith(Suite.class)
#SuiteClasses({SQLServerTests1.class, SQLServerTest2.class, ... })
public class AllSQLServerTests {}
However I have almost 100+ classes and I don't want to have to remember to include any new one in the #SuiteClasses annotation.
As my classes have a naming convention (starting with "SQLServer" for example) I am searching for a way to do something like this:
#RunWith(Suite.class)
#SuiteClasses(prefix="SQLServer")
public class AllSQLServerTests {}
is it possible with plain JUnit? with spring or any other framework?
Tag'em
You can add many tags to each test or test class:
#Test
#Tag("red")
#Tag("production")
public void testWithColour() {...}
#RunWith(JUnitPlatform.class)
#IncludeTags("red & !production")
public class JUnit5Example {
//...
}
You can also use #ExcludeTags but it cannot co-exist with #IncludeTags
Run all in test package
#RunWith(JUnitPlatform.class)
#SelectPackages("com.acme.megaproduct.slowtests")
public class JUnit5Example {
//...
}
Write custom Test Runner
Perhaps none of the above can acommodate your needs, in which case you can add custom filtering by writing your own runner.
See here for step by step how to do it.
Then you just use it like:
#RunWith(MyCustomRunner.class)
public class CustomTestSuite {
//...
}

How to give warning message in own API?

Is that possible to give custom warning message in my own API like below? Is Resource leak:'ois' is never closed message related with Java API or JVM?
It's possible using a compiler API. You have to extend an AbstractProcessor and then make sure compiler knows about it.
Lets say we don't like programmers to swear in the source code. So, when someone defines a field with name "shit", we want to show a warning. Here is a simple implementation:
import java.util.List;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;
#SupportedSourceVersion(SourceVersion.RELEASE_7)
#SupportedAnnotationTypes("*")
public class Test extends AbstractProcessor {
public int shit;
public int foo;
#Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
Set<? extends Element> rootElements = roundEnv.getRootElements();
for (Element element : rootElements) {
if (element.getKind() == ElementKind.CLASS) {
List<? extends Element> classElements = element.getEnclosedElements();
for (Element classElement : classElements) {
if (classElement.getKind() == ElementKind.FIELD) {
if (classElement.getSimpleName().contentEquals("shit")) {
processingEnv.getMessager().printMessage(
Kind.WARNING,
"How dare you to swear in the source code?!",
classElement
);
}
}
}
}
}
return false;
}
public static void main(String[] args) {
//
}
}
Now, we want to apply such a processor just for this very class, because there is an ugly bad-called field too.
Using a command line:
javac Test.java
javac -processor Test Test.java
We need to firstly build a processor and then apply it while compiling (in this case to the same file).
And this is the output we get:
Test.java:17: warning: How dare you to swear in the source code?!
public int shit;
^
1 warning
To have the same warning in Eclipse or any other IDE, it's necessary to change compiler settings so it uses this custom processor.
Update: In the comments, kapep sent a link on how to set a custom processor in Eclipse: http://kerebus.com/2011/02/using-java-6-processors-in-eclipse/
Just for the record: Exactly the same warning may be achieved by implementing interface Closeable:
import java.io.Closeable;
import java.io.IOException;
public class Test implements Closeable {
#Override
public void close() throws IOException {
// TODO Auto-generated method stub
}
public static void main(String[] args) {
new Test();
}
}
And you see the same warning:
You can create warnings, notes, errors and other diagnostic messages like this using an annotation processor. It's a compiler plugin api integrated in the JDK. It lets you analyse the outline structure of source code. Despite the name you don't really need to handle any annotation when processing code. Messages are created using the Messager class. If you provide an element, it will be marked and the message will be shown next to it in the source code editor.
You won't be able to show message on elements inside methods or expressions though, only on declarations like types, properties, methods or parameters. It's possible to additionally parse the method body and generate messages based on the content using other tools, but as far as I know you can't show the message on the actual local element then. You could still show the message on the enclosing method or don't specify any element at all and show it in the IDE's log.
The IDE also needs to support this. I know that Eclipse and NetBeans do support messages generated by annotation processors, but there are probably other modern IDE that do so as well. If you need more features like messages on elements inside method bodies or the quick fix feature as shown in the example, I guess you need to create a plugin for the IDE.
I would believe that it is related to the eclipse ide, you could possibly write a plugin which displays warnings like that.
For example, when you use a method which has the annotation '#Deprecated' the ide automatically tells the programmer that the method is deprecated.

How to make annotation deprecated only on one target

I have an annotation that can be added on METHOD and TYPE and is used in thousands of places in our project.
#Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
#Target({METHOD, TYPE})
#Inherited
public #interface RequiredStore{
Store value();
}
Is it possible to make the annotation deprecated only on methods while keeping it non-deprecated on types? I want other developers to be notified by IDE that it should not be used on methods any more, until we'll refactor all existing usages and finally remove the METHOD part.
If it's not possible, is there any Way to handle such case beside creating new annotation only for types and deprecating the old one?
You could use an annotation Processor.
For example, the annotation and its processor would be placed in its own .jar file and added as a dependency of the sources that use the annotation.
The custom .jar would have the following structure:
src/main/
java/com/company/annotations/
RequiredStore.java
RequiredStoreProcessor.java
resources/META-INF/services
javax.annotation.processing.Processor
RequiredStore.java stays as you have it above.
RequiredStoreProcessor.java could look something like this:
package com.company.annotations;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
#SupportedAnnotationTypes("com.company.annotations.RequiredStore")
public class RequiredStoreProcessor extends AbstractProcessor {
#Override
public boolean process(
Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
for (Element element
: roundEnv.getElementsAnnotatedWith(RequiredStore.class)) {
if (element.getKind().equals(ElementKind.METHOD)) {
processingEnv.getMessager().printMessage(
Diagnostic.Kind.WARNING,
"Using #RequiredStore on methods has been deprecated\n"
+ "Class: " + element.getEnclosingElement() + "\n"
+ "Method: " + element.getSimpleName() + "\n");
}
}
// Other processing...
return false;
}
#Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latest();
}
}
The javax.annotation.processing.Processor file allows javac to pickup the Processor via SPI and simply contains
com.company.annotations.RequiredStoreProcessor
Finally, compile this into a .jar and add it to the classpath where the annotations are being used. Any methods that have the #RequiredStore will produce a compiler warning. For example, for this class,
package com.company.business;
import com.company.annotations.RequiredStore;
#RequiredStore
public interface Business {
#RequiredStore
public void someMethod();
}
The compiler warning would be this:
warning: Using #RequiredStore on methods has been deprecated
Class: com.company.business.Business
Method: someMethod
As for an indication in the IDE, you might have to write a custom inspection and unfortunately this depends on the IDE used.
Notes:
Decent custom annotations reference: Code Generation using Annotation Processors in the Java language
If you are okay about using native aspectj, another option is to use AspectJ's code enforcement policy this way:
public aspect RequiredStoreAnnotationCheck {
declare warning: execution(#RequiredStore * *.*(..)) : "Required store annotation not appropriate for methods..";
}
If the IDE is integrated with AspectJ, this would be flagged as a compile time check.
AspectJ in action book has a good amount of detail on this too.
Here is one of my blog articles for more context: http://www.java-allandsundry.com/2012/03/code-policy-enforcement-using-aspectj.html

Play Framework Dependency Injection

I've been looking all over Google to find some useful information on how to use Guice/Spring DI in Play Framework 2.1
What I want to do is to Inject several Services in some DAO's and vice versa.
Just need some clarification on this - With play 2.1, do you have to use an # annotation within the routes file for DI?
I've looked at this guide here - https://github.com/playframework/Play20/blob/master/documentation/manual/javaGuide/main/inject/JavaInjection.md
and applied the following steps creating a Global class in app and adding the GUICE dependencies in Build.scala but keep on getting a null pointer exception when invoking on the injected object.
Has anyone been able to get DI working in Play 2.1 using Guice? I've seen examples across the internet but they all seem to be using DI within the controller.
I noticed you are using Java. Here is how I got it to work for injecting into a controller.
First, I created the following 4 classes :
MyController:
package controllers;
import play.mvc.*;
import javax.inject.Inject;
public class MyController extends Controller {
#Inject
private MyInterface myInterface;
public Result someActionMethodThatUsesMyInterface(){
return ok(myInterface.foo());
}
}
MyInterface:
package models;
public interface MyInterface {
String foo();
}
MyImplementation2Inject:
package models;
public class MyImplementation2Inject implements MyInterface {
public String foo() {
return "Hi mom!";
}
}
MyComponentModule:
package modules;
import com.google.inject.AbstractModule;
import models.MyInterface;
import models.MyImplementation2Inject;
public class ComponentModule extends AbstractModule {
#Override
protected void configure() {
bind(MyInterface.class).
to(MyImplementation2Inject.class);
}
}
Now the final part, that took me a silly long time to figure out, was to register the module. You do this by adding the following line to the end of the application.conf file, which is located in the conf directory:
play.modules.enabled += "modules.MyComponentModule"
I hope this was helpful to you. :)
I use cake pattern and my own version of Global overriding getControllerInstance
https://github.com/benjaminparker/play-inject
Cheers
Ben
Sorry, this is a late response, but here's our example
https://github.com/typesafehub/play-guice
Have you tried using some different approach to DI than Guice?
We also tried implementing a project with Guice or Spring but ended in registering our dependencies in objects that implement trait such as:
trait Registry {
def userDao: UserDao
...
}
object Registry {
var current: Registry = _
}
object Environnment {
object Dev extends Registry {
val userDao = ...
//implement your environment for develpment here
}
object Test extends Registry {
val userDao = ...
//implement your ennviroment for tests here e.g. with mock objects
}
}
Another good approach wich might fit for you is the cake pattern (just google for it).

Can I specify a class wide group on a TestNG test case?

I have a base class that represents a database test in TestNG, and I want to specify that all classes extending from this class are of a group "db-test", however I have found that this doesn't seem possible. I have tried the #Test annotation:
#Test(groups = { "db-test" })
public class DBTestBase {
}
However, this doesn't work because the #Test annotation will try to make a bunch of methods into tests, and warnings/errors pop up in eclipse when the tests are run.
So I tried disabling the test, so at least the groups are assigned:
#Test(enabled = false, groups = { "db-test" })
public class DBTestBase {
}
but then any #BeforeTest (and other similar annotations) ALSO get disabled... which is of course not what I want.
I would like some way to annotate a class as being of a particular type of group, but it doesn't quite seem possible in TestNG. Does anyone have any other ideas?
TestNG will run all the public methods from a class with a #Test annotation. Maybe you could change the methods you don't want TestNG to run to be non-public
The answer is through a custom org.testng.IMethodSelector:
Its includeMethod() can exclude any method we want, like a public not-annotated method.
However, to register a custom Java MethodSelector, you must add it to the XMLTest instance managed by any TestRunner, which means you need your own custom TestRunner.
But, to build a custom TestRunner, you need to register a TestRunnerFactory, through the -testrunfactory option.
BUT that -testrunfactory is NEVER taken into account by TestNG class... so you need also to define a custom TestNG class :
in order to override the configure(Map) method,
so you can actually set the TestRunnerFactory
TestRunnerFactory which will build you a custom TestRunner,
TestRunner which will set to the XMLTest instance a custom XMLMethodSelector
XMLMethodSelector which will build a custom IMethodSelector
IMethodSelector which will exclude any TestNG methods of your choosing!
Ok... it's a nightmare. But it is also a code-challenge, so it must be a little challenging ;)
All the code is available at DZone snippets.
As usual for a code challenge:
one java class (and quite a few inner classes)
copy-paste the class in a 'source/test' directory (since the package is 'test')
run it (no arguments needed)
Update from Mike Stone:
I'm going to accept this because it sounds pretty close to what I ended up doing, but I figured I would add what I did as well.
Basically, I created a Groups annotation that behaves like the groups property of the Test (and other) annotations.
Then, I created a GroupsAnnotationTransformer, which uses IAnnotationTransformer to look at all tests and test classes being defined, then modifies the test to add the groups, which works perfectly with group exclusion and inclusion.
Modify the build to use the new annotation transformer, and it all works perfectly!
Well... the one caveat is that it doesn't add the groups to non-test methods... because at the time I did this, there was another annotation transformer that lets you transform ANYTHING, but it somehow wasn't included in the TestNG I was using for some reason... so it is a good idea to make your before/after annotated methods to alwaysRun=true... which is sufficient for me.
The end result is I can do:
#Groups({ "myGroup1", "myGroup2"})
public class MyTestCase {
#Test
#Groups("aMethodLevelGroup")
public void myTest() {
}
}
And I made the transformer work with subclassing and everything.
It would seem to me as the following code-challenge (community wiki post):
How to be able to execute all test methods of Extended class from the group 'aGlobalGroup' without:
specifying the 'aGlobalGroup' group on the Extended class itself ?
testing non-annotated public methods of Extended class ?
The first answer is easy:
add a class TestNG(groups = { "aGlobalGroup" }) on the Base class level
That group will apply to all public methods of both Base class and Extended class.
BUT: even non-testng public methods (with no TestNG annotation) will be included in that group.
CHALLENGE: avoid including those non-TestNG methods.
#Test(groups = { "aGlobalGroup" })
public class Base {
/**
*
*/
#BeforeClass
public final void setUp() {
System.out.println("Base class: #BeforeClass");
}
/**
* Test not part a 'aGlobalGroup', but still included in that group due to the class annotation. <br />
* Will be executed even if the TestNG class tested is a sub-class.
*/
#Test(groups = { "aLocalGroup" })
public final void aFastTest() {
System.out.println("Base class: Fast test");
}
/**
* Test not part a 'aGlobalGroup', but still included in that group due to the class annotation. <br />
* Will be executed even if the TestNG class tested is a sub-class.
*/
#Test(groups = { "aLocalGroup" })
public final void aSlowTest() {
System.out.println("Base class: Slow test");
//throw new IllegalArgumentException("oups");
}
/**
* Should not be executed. <br />
* Yet the global annotation Test on the class would include it in the TestNG methods...
*/
public final void notATest() {
System.out.println("Base class: NOT a test");
}
/**
* SubClass of a TestNG class. Some of its methods are TestNG methods, other are not. <br />
* The goal is to check if a group specify in the super-class will include methods of this class. <br />
* And to avoid including too much methods, such as public methods not intended to be TestNG methods.
* #author VonC
*/
public static class Extended extends Base
{
/**
* Test not part a 'aGlobalGroup', but still included in that group due to the super-class annotation. <br />
* Will be executed even if the TestNG class tested is a sub-class.
*/
#Test
public final void anExtendedTest() {
System.out.println("Extended class: An Extended test");
}
/**
* Should not be executed. <br />
* Yet the global annotation Test on the class would include it in the TestNG methods...
*/
public final void notAnExtendedTest() {
System.out.println("Extended class: NOT an Extended test");
}
}
I'm not sure how the annotation inheritance works for TestNG but this article may be of some use.
Actually, this may help better, look at inheritGroups.
You can specify the #Test annotation at method level that allows for maximum flexibility.
public class DBTestBase {
#BeforeTest(groups = "db-test")
public void beforeTest() {
System.out.println("Running before test");
}
public void method1() {
Assert.fail(); // this does not run. It does not belong to 'db-test' group.
}
#Test(groups = "db-test")
public void testMethod1() {
Assert.assertTrue(true);
}
}
Does this works for you or I am missing something from your question.

Categories

Resources