Conditional execution of a method using annotation - java

In java can I have conditional execution of a method using annotations?
I wish to have some system property set and based on that system property I wish to either execute or not execute a method (specifically ant script based JUnits) at runtime.
Please let me know if it's possible using the annotations.

I think that you can implement it in Java but I suggest you to take a look on Spring AOP - I believe that this is what you are looking for.

You can group tests by #Category and tell the running to include this category.
From http://alexruiz.developerblogs.com/?p=1711
public interface FastTests { /* category marker */ }
public interface SlowTests { /* category marker */ }
public class A {
#Category(SlowTests.class)
#Test public void a() {}
}
#Category(FastTests.class})
public class B {
#Test public void b() {}
}
#RunWith(Categories.class)
#IncludeCategory(SlowTests.class)
#ExcludeCategory(FastTests.class)
#SuiteClasses({ A.class, B.class })
public class SlowTestSuite {}

You can implement your own TestRunner or user AOP for this.

An annotation, in the Java computer programming language, is a form of syntactic metadata that can be added to Java source code. Classes, methods, variables, parameters and packages may be annotated.
Take a look at this

I'd write a simple custom test runner by extending BlockJUnit4ClassRunner. That runner would read a configuration from a system property or a configuration file to only run the defined tests. The simplest solution would be a blacklist to exclude selected methods, because the default behaviour of this (default!) runner is to run every test.
Then just say
#RunWith(MyTestRunner.class)
public void TestClass {
// ...
}
For the implementation, it could be sufficiant to just overwrite the getChildren() method:
#Overwrite
List<FrameworkMethod> getChildren() {
List<FrameworkMethod> fromParent = super.getChildren();
List<FrameworkMethod> filteredList = new ArrayList(filter(fromParent));
return filteredList;
}
where filter checks for every FrameworkMethod whether it should be executed or not according to the "blacklist", that has been created based on the property.

Related

Make SonarQube ignore empty test classes

I have multiple production classes "NaiveHandler", "SmartHandler", "AnotherHandler" that implement the same interface "Handler" and share a lot of code. To reduce code duplication, I extracted an abstract class "AbstractHandler" that contains most of the code, and let the sub-classes inherit and reuse it.
Similarly, the test classes "NaiveHandlerTest", "SmartHandlerTest", "AnotherHandlerTest" for those production classes held tons of duplicate test methods. I moved all these #Test-annotated methods and the test setup out into an abstract class called "HandlerTestBase".
abstract class HandlerTestBase {
protected Handler cut;
protected SomeDependency x;
protected abstract Handler getCutInstance(SomeDependency x);
#BeforeEach
void setup() {
x = Mockito.mock(SomeDependency.class);
cut = getCutInstance(x);
}
#Test
void providesTheRightThing() {
when(x.getSomeValue()).thenReturn("zzz");
var result = cut.doSomething("a");
assertThat(result).isEqualTo("b");
}
// more tests that verify the shared code in AbstractHandler
}
This abstract class cannot (and should not) run on its own. The "~Base" at the end prevents Maven's tools from picking it up and running it. Instead, Maven picks up the individual test classes "NaiveHandlerTest", "SmartHandlerTest", "AnotherHandlerTest", and runs those.
class SmartHandlerTest extends HandlerTestBase {
#Override
protected Handler getCustInstance(SomeDependency x) {
return new SmartHandler(x);
}
// here more tests that only relate to SmartHandler, not the shared code, e.g.
#Test
void specificClassDoesTheRightThing() {
when(x.getSomeValue()).thenReturn("12345");
var result = cut.doSomething("a");
assertThat(result).isEqualTo("y");
}
}
All of this works beautifully.
As one consequence however, one of the test sub-classes, "NaiveHandlerTest" is now empty. It inherits the tests from the abstract class and runs those, but doesn't add any specific tests of its own. For me, this is not a problem.
class NaiveHandlerTest extends HandlerTestBase {
#Override
protected Handler getCustInstance(SomeDependency x) {
return new NaiveHandler(x);
}
}
However, SonarQube picks out this class and reports the code smell "Add some tests to this class", saying that "There's no point in having a JUnit TestCase without any test methods." For other cases, I would agree, but in this pattern SonarQube does not recognize that the test class may look empty but inherits and runs test methods from its super-class.
I could set this finding to "False Positive" to remove it. I could also annotate the seemingly empty test class with #java.lang.SuppressWarnings("java:S2187") to switch off this check here. Is there a still better way to get rid of this finding, such as a tiny tweak to the design that makes SonarQube aware of the existing tests?

Is it OK to inject value directly inside Bean function?

I was wondering how to do dependency injection in the most effective way inside my code.
I have this code:
#Configuration
public class SomeName {
#Autowired
private Other other;
#Bean
public void method() {
other.someMethod();
// some code
}
}
Can this code be changed into the following code(other will be used only inside this function)?
#Configuration
public class SomeName {
#Bean
public void method(Other other) {
other.someMethod();
// some code
}
}
You should avoid #Autowired if possible and inject using a constructor or method.
Starting with Java 9 and java modules (project jigsaw) there are some strict rules that make it harder for your framework to change the values of a private field.
What Spring is doing in the first example is essentially that - it breaks encapsulation to change the value of a private value. (There is a way to overcome this with "opens" directive in module-info..)
You are also becoming dependent on the framework you are using and your code becomes harder to test compared to when using a simple setter.
You are also not explicitly declaring that your class depends on another class since I can easily instantiate it and "Other" will be null.
Some resources:
https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-scanning-autodetection (search for jigsaw)
https://blog.marcnuri.com/field-injection-is-not-recommended/
PS: You are probably missing #Configuration on your class

Is it possible to have a global setup method in Spock test?

I am a developer on a Grails/Groovy application which uses Spock as its framework for unit testing. The project has around 1000 unit tests, and I would essentially like to perform a specific mock / operation before running all tests. Preferably it should only be executed once, alternatively before each test - or before some large subset of all the tests. I imagine that it out to be possible to have a “global” setup method which all tests can extend. Is this possible?
Preferably it should only be executed once, alternatively before each
test - or before some large subset of all the tests. I imagine that it
out to be possible to have a “global” setup method which all tests can
extend. Is this possible?
Yes, it is possible. The specifics of how best to do it will depend on specifically what you want to accomplish but global extensions are likely candidates. See the "Writing Custom Extensions" section of http://spockframework.org/spock/docs/1.3/extensions.html for a lot of detail. There is a lot of flexibility there. We had great success writing custom extensions for Micronaut.
I hope that helps.
We ended up doing the following. First we defined a class implementing IAnnotationDrivenExtension interface:
class MockConfigMapExtension implements IAnnotationDrivenExtension<MockConfigMap> {
#Override
void visitSpecAnnotation(MockConfigMap annotation, SpecInfo spec) {
// WRITE THE RELEVANT STARTUP CODE HERE
}
#Override
void visitFeatureAnnotation(MockConfigMap annotation, FeatureInfo feature) {
}
#Override
void visitFixtureAnnotation(MockConfigMap annotation, MethodInfo fixtureMethod) {
}
#Override
void visitFieldAnnotation(MockConfigMap annotation, FieldInfo field) {
}
#Override
void visitSpec(SpecInfo spec) {
}
}
where we defined this trivial annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target([ElementType.TYPE])
#ExtensionAnnotation(MockConfigMapExtension.class)
#interface MockConfigMap {
}
Now, whenever we annotate a Spec class with the MockConfigMap annotation, the visitSpecAnnotation method is invoked, and we get the desired behaviour.

Extending from Suite Runner vs BlockJUnit4Runner while defining some TestRules

I have a requirement to write many tests. I have extended Suite Runner of JUnit in order to be able to add new annotations where I can mention several Prerequisite classes which will be executed before any of the tests or setups get executed. My Typical test looks like this.
#RunWith(CustomSuiteRunner.class)
#BeforeSuite(Prerequisite.class)
#AfterSuite(CleanupOperations.class)
#Suite.SuiteClasses({
SimpleTests.class,
WeatherTests.class
})
public class SimpleSuite {
}
I have overridden public void run(final RunNotifier notifier) to add code the required code to trigger prerequisites and cleanup operations mentioned in BeforeSuite and AfterSuite annotation.
Now, I'm trying to find out how I can achieve the same by extending BlockJUnit4Runner? I can't find any method equivalent to run that starts the execution to override the behaviour. There is runChild which gets triggered before a child gets executed.
The reason I'm looking for this is I'm trying created several rules in an Interface and make my tests implement that so that they will be available, however as Interface elements are static and final JUnit is ignoring these. In another Question I asked today I got answer that I can make JUnit consider rules mentioned in an Interface by extending BlockJUnit4Runner and overriding getTestRules().
So, Here is what I'm trying find out.
Is it possible to extend BlockJUnit4Runner to make it take a list of tests and run them as suite and also run some code before any tests get execute and after all tests are executed?
How can I extend Suite Runner to consider TestRules defined in an implemented interface?
It is pretty much possible to extend BlockJUnit4Runner and make it take a list of tests and run them as suite with required test dependencies handled within the extended runChild() method
public class CustomRunner extends BlockJUnit4ClassRunner {
private List<String> testsToRun = Arrays.asList(new String[] { “sample1” });
public CustomRunner(Class<?> klass) throws InitializationError {
super(klass);
}
public void runChild(FrameworkMethod method, RunNotifier notifier) {
//Handle any dependency logic by creating a customlistener registering notifier
super.runChild(method,notifier);
}
}

custom annotation on class and method

Is it possible that I put custom annotation on class and then it forceful the developer to put the annotation on method?
suppose I have three custom annotation
#Loggable
#MySQLLoggable
#CassandraLoggable
when I put #Loggble annotation on class , it forceful the developer to annotate its all methods either by #MySQLLoggable or #CassandraLoggable.
update me!
EDITED
#Loggable // Suppose I put this annotation on class
public class Service {
#MySQLLoggable //eclipse forceful the developer
//to put #MySQLLoggable or #CassandraLoggable on sayHello()
public String sayHello() {
return null;
}
}
use #interface
public #interface foo {
String str();
}
#foo(str = "str")
public class myClass{
}
edit
public #interface loggable {
#loggable1(method) #loggable2(method))
String foo();
}
Sorry if you want that IDE make developers use your custom annotations then you better read your IDE specification and possible customization. If you want that later on during execution your app will throw exceptions if methods are not annotated then you have to use reflection. Let's save you use Factory Pattern to create objects. So before create them you can check whether all methods are annotated and if not all then throw an exception. Again I believe you have to use reflection.. this is only one way!

Categories