JUnit 5 TestTemplates and Extensions: Accessing TestTemplateInvocationContext? - java

Use case:
A test shall be executed with different parameters.
For this test we want to use an extension doing some pre-/postprocessing. This step needs access to the current set parameter.
Initially I tried implementing this with a #ParameterizedTest. Here the extension has no chance to access the parameter (The parameter is evaluated after the beforeTestExecution call). As a matter of this I used #TemplateTest with TestTemplateInvocationContextProvider (as described in the guide). Now I could see my parameters in the extensionContext. Unfortunately there are accessor methods missing for that:
on MethodExtensionContext (resp. super class): getTestDescriptor() : TestTemplateInvocationTestDescriptor
on TestTemplateInvocationTestDescriptor: getInvocationContext()
As a hopefully temporary workaround I do some reflection to access my invocationContext.
Is there something that tells against introducing these accessor methods? Is there even a better / simpler way for doing this?

I think you can provide additional Extensions in the TestTemplateInvocationContext. The following is based on the example in the user guide:
#TestTemplate
#ExtendWith(MyTestTemplateInvocationContextProvider.class)
void testTemplate(String parameter) {
System.out.println("Test with parameter: " + parameter);
assertEquals(3, parameter.length());
}
static class MyTestTemplateInvocationContextProvider implements TestTemplateInvocationContextProvider {
#Override
public boolean supportsTestTemplate(ExtensionContext context) {
return true;
}
#Override
public Stream<TestTemplateInvocationContext> provideTestTemplateInvocationContexts(ExtensionContext context) {
return Stream.of(invocationContext("foo"), invocationContext("bar"));
}
private TestTemplateInvocationContext invocationContext(String parameter) {
return new TestTemplateInvocationContext() {
#Override
public String getDisplayName(int invocationIndex) {
return parameter;
}
#Override
public List<Extension> getAdditionalExtensions() {
return Arrays.asList(parameterResolver(), preProcessor(), postProcessor());
}
private BeforeTestExecutionCallback preProcessor() {
return new BeforeTestExecutionCallback() {
#Override
public void beforeTestExecution(ExtensionContext context) throws Exception {
System.out.println("Pre-process parameter: " + parameter);
}
};
}
private AfterTestExecutionCallback postProcessor() {
return new AfterTestExecutionCallback() {
#Override
public void afterTestExecution(ExtensionContext context) throws Exception {
System.out.println("Post-process parameter: " + parameter);
}
};
}
private ParameterResolver parameterResolver() {
return new ParameterResolver() {
#Override
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {
return parameterContext.getParameter()
.getType()
.equals(String.class);
}
#Override
public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {
return parameter;
}
};
}
};
}
}
The console output is:
Pre-process parameter: foo
Test with parameter: foo
Post-process parameter: foo
Pre-process parameter: bar
Test with parameter: bar
Post-process parameter: bar

This would mean that I have to one extension to the other. Currently I have two extensions: One (MyProvider) implementing TestTemplateInvocationContextProvider (used for test parametrization) and one (MyCallback) implementing BeforeTestExecutionCallback for doing some preparation work.
This looks like:
#ExtendWith(MyCallback.class)
public class WebTest {
#TestTemplate
#ExtendWith(MyProvider.class)
public void showPage() throws Exception {
}
}
My goal would be getting the current parameter in the class level extension:
public class MyCallback implements BeforeAllCallback, BeforeTestExecutionCallback {
public void beforeAll(ExtensionContext ctx) {
}
public void beforeTestExecution(ExtensionContext ctx) {
// HERE I WANT CURRENT PARAMETER VALUE:
((TestTemplateInvocationTestDescriptor) ((MethodExtensionContext) ctx).testDescriptor).invocationContext;
}
If I had two public methods added (as mentioned in first edit) it would be possible but maybe it is against the concept?

Related

How to verify a method was called inside another method with Mockito

I'm fairly new to Mockito, and I've been looking for a way to verify that if I call the filter() method with the right string, that the foo method will get called once.
public class A
{
private final Config _config;
public A(Config config) { _config = config; }
public void filter(String str)
{
if(str.startsWith("a"))
{
if(str.contains("z"))
{
foo(config.getName());
}
}
}
private void foo(String bar)
{
(...)
}
}
Here is my current code:
#Test
public void testOne()
{
Config config = new Config(configFile);
A a = Mockito.spy(new A(config));
a.filter("abcz");
verify(a, times(1)).foo(someString);
}
Try to be more generic while such a test. If you don't need to specify what exactly argument should by passed then just use any():
import static org.mockito.ArgumentMatchers.any;
verify(a).foo(any(String.class));

Composition and generics

I'm trying to solve this "composition + generics" situation, and make PostCompany.send(msg) be compatible with the type passed/injected to the class.
What could I change to allow both Fedex and FedexPlus being used as generic Types at PostCompany class, since Fexed's send method expects String as parameter and FeexPlus expects Integer?
interface Poster<T> {
void send(T msg);
}
class Fedex implements Poster<String> {
#Override
public void send(String msg) {
// do something
}
}
class FedexPlus implements Poster<Integer> {
#Override
public void send(Integer msg) {
// do something
}
}
class PostCompany<P extends Poster> {
private final P poster;
public PostCompany(P poster) {
this.poster = poster;
}
public void send(??? msg) { // <-- Here
this.poster.send(msg);
}
}
You missed the type of a Poster
class PostCompany<T, P extends Poster<T>> {
public void send(T msg) { // <-- Here
this.poster.send(msg);
}
}
But it actually better to just type the type of the object
class PostCompany<T> {
private final Poster<T> poster;
public PostCompany(Poster<T> poster) {
this.poster = poster;
}
public void send(T msg) { // <-- Here
this.poster.send(msg);
}
}
Since you will always be using the interface methods of Poster
You are using the raw form of Poster when defining PostCompany. You need to define another type parameter to capture the type argument for Poster.
Then you can use that new type parameter as the type argument to Poster and as the parameter type to the send method.
class PostCompany<T, P extends Poster<T>> {
and
public void send(T msg) {

How to modify/decorator an object returned from 3rd party API using javassist/CGLib

I have an 3rd party API call which returns the following object:
public class A {
protected void common() {
System.out.println("common is called in A");
}
public void test1() {
common();
System.out.println("test1 is called in A");
}
public void test2() {
common();
System.out.println("test2 is called in A");
}
}
But I'd like to modify its behavior like the following ModifiedA shows:
public class ModifiedA extends A {
#Override
protected void common() {
super.common();
System.out.println("common is called in ModifiedA");
}
}
So what I am trying to do is:
A a = 3rdPartyAPI_call();
//
// Now I'd like to get a ModifiedA which has changed common() behavior.
//
How to use javassist/CGLIB to accomplish this ?
One easy way may be to like this:
public class ModifiedA extends A {
private A a;
public ModifiedA(final A a) {
this.a = a;
}
//
// Override every public method in A
//
#Override
protected void common() {
super.common();
System.out.println("common is called in ModifiedA");
}
}
But since A's definition comes from 3rd party and is very complex and may change, so I'd like to use a proxy to do this?
Thanks for your comments in adavance.
You can use CGLib to implement a delegator pattern without having to override all the methods. There are a few different approaches to implement this depending on style but here is one similar to your example.
You can wrap the instance using a cglib Enhancer:
public static <T> T wrapInstance(final T original) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(original.getClass());
enhancer.setCallback(new MethodInterceptor() {
#Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
Object returnValue = proxy.invoke(original, args);
if (method.getName().equals("common")) {
System.out.println("common is called");
}
return returnValue;
}
});
return (T) enhancer.create();
}
eclps post will fullfill your requirement and it works.I want to add some more code to eclps code.
Adding filter which give index zero for common method and rest all method to One. MethodInterceptor callback will intercept only common method and rest all method use NoOp intercetor(which will call super class apis).This way filtering is not happening for every method call.
public static <T> T wrapInstance(final T original) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(original.getClass());
enhancer.setCallbackFilter(new CallbackFilter() {
#Override
public int accept(Method method) {
if (method.getName().equals("common")) {
return 0;
}
return 1;
}
});
enhancer.setCallbacks(new Callback[]{new MethodInterceptor() {
#Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// only common method will intercept this call back.
return proxy.invoke(this, args);
}
}, NoOp.INSTANCE});
return (T) enhancer.create();
}

Conditional matching in Google Guice

I have a MethodInterceptor bound to methods in a class in order to do some simple logic before on the data before the class gets to touch it.
However, teh class itself makes calls to some of its own intercepted methods, but at that point I don't need to re-run that logic anymore.
public class MyModule extends AbstractModule {
#Override
public void configure() {
bindInterceptor(Matchers.any(), Matchers.annotatedWith(MyAnnotation.class), new MyInterceptor());
}
}
public class MyInterceptor implements MethodInterceptor {
#Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// logic
}
}
public MyClass {
#MyAnnotation
void foo() {
bar();
}
#MyAnnotation
void bar() {
}
}
Is there a way for the call for bar within foo to not be itnercepted?
To be honest, the easiest solution is to simply avoid the problem by never calling another public/annotated method of the same class from within the class:
public class MyClass {
#MyAnnotation
public void foo() {
doBar();
}
#MyAnnotation
public void bar() {
doBar();
}
private void doBar() {
//doesn't go through interceptor
}
}
If for some reason that's not an option, then you might look at this approach. More expressive AOP libraries like AspectJ give you a greater level of flexibility for defining a pointcut.
In Guice, the pointcut is simply a method with an annotation belonging to an instance instantiated by Guice. So this logic has to be moved to the interceptor itself.
One approach for doing so might be to use a ThreadLocal to track entries into the interceptor. Extending something like this might be a start:
public abstract class NonReentrantMethodInterceptor implements MethodInterceptor {
private final ThreadLocal<Deque<Object>> callStack = new ThreadLocal<>();
#Override
public final Object invoke(MethodInvocation invocation) throws Throwable {
Deque<Object> callStack = this.callStack.get();
if (callStack == null) {
callStack = new LinkedList<>();
this.callStack.set(callStack);
}
try {
return invokeIfNotReentrant(callStack, invocation);
} finally {
if (callStack.isEmpty()) {
this.callStack.remove();
}
}
}
private final Object invokeIfNotReentrant(Deque<Object> callStack, MethodInvocation invocation) throws Throwable {
Object target = invocation.getThis();
if (callStack.isEmpty() || callStack.peek() != target) {
//not being called on the same object as the last call
callStack.push(target);
try {
return doInvoke(invocation);
} finally {
callStack.pop();
}
} else {
return invocation.proceed();
}
}
protected abstract Object doInvoke(MethodInvocation invocation) throws Throwable;
}
This uses a thread local stack to track the stack of calls into the interceptor. When the last call into this interceptor targeted the same object, it calls proceed() and bypasses the interceptor. When this is the first call into the interceptor, or if the last call was not targeting the same object, it applies the interceptor.
Then the actual logic you would want to apply when the interceptor is active would go into doInvoke().
Example usage:
public class NonReentrantTester {
public static void main(String[] args) {
Injector injector = Guice.createInjector(new Module());
MyClass instance = injector.getInstance(MyClass.class);
instance.foo();
}
static class Module extends AbstractModule {
#Override
protected void configure() {
bindInterceptor(Matchers.any(), Matchers.annotatedWith(PrintsFirstInvocation.class),
new PrintsFirstInvocationInterceptor());
}
}
public static class MyClass {
#PrintsFirstInvocation
void foo() {
bar();
}
#PrintsFirstInvocation
void bar() {
}
}
public static class PrintsFirstInvocationInterceptor extends NonReentrantMethodInterceptor {
#Override
protected Object doInvoke(MethodInvocation invocation) throws Throwable {
System.out.println(invocation.getMethod());
return invocation.proceed();
}
}
#BindingAnnotation
#Target({FIELD, PARAMETER, METHOD})
#Retention(RUNTIME)
public #interface PrintsFirstInvocation {
}
}

Method as parameter with signature contract?

I would like to know how to create a contract with the caller for the Method parameter in the event the method has parameters itself. So that I use...
ClassA {
String string_ = "HI";
public static void subscribe(Object class, Method action) {
action.invoke(class, string_);
}
}
ClassB {
ClassB() {
ClassA.subscribe(this, this.getClass().getMethod("load", String.class));
}
public void load(String input) {
if(input.equals("HI")) {
...
}
}
}
I would like to know how to ensure the Method passed as "action" takes String as a parameter (i.e. ensure Method action == load(String){})? Is there something like this available:
public static void subscribe(Object class, Method action(String.class)) {
I want to do it in the method signature of subscribe so that it is obvious to the calling class (ClassB) that it needs to be prepared to take an argument of specified type.
EDIT: Updated last code bit so not to appear as if Method was generic. Poor choice of using <> on my part to represent an example of what I was trying to convey.
There's no way to do that in Java. The Method class is not generic, and there is no way for it to be so, because methods can take any number of parameters, and there is no way to make a class generic over a variable number of types.
Probably the best you can do is to declare your own type to use instead of Method:
public interface Action<T, P> {
public void invoke(T target, P parameter);
}
Then:
public static <T> void subscribe(T obj, Action<T, String> action) {
action.invoke(obj, string_);
}
ClassB() {
ClassA.subscribe(this, new Action<ClassB, String>() {
public void invoke(ClassB target, String parameter) {
target.load(parameter);
}
});
}
In C# there are means to achieve what you are trying to do but I can't think of a way to ensure that at compile time for java.
can you resort to using intefaces?
interface ILoader{
void load(String input);
}
ClassA {
String string_ = "HI";
public static void subscribe(ILoader loader) {
loader.load( string_);
}
}
ClassB implements ILoader {
ClassB() {
ClassA.subscribe(this);
}
public void load(String input) {
if(input.equals("HI")) {
...
}
}
}
Couldn't you use a slight modification of the Command Pattern?
puclic interface LoadCommand {
public load(String input);
}
public class ClassB implements LoadCommand {
public load(String input) {
// do stuff here
}
}
public class ClassA {
String myInput = "HI";
public static void subscribe(LoadCommand command) {
command.load(myInput)
}
}
The load method in the LoadCommand interface takes one String argument.

Categories

Resources