IReporter is an interface that has a single void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) method. I would like to make the behavior of the reporter configurable so I can pass options to it when run on the commandline. The documentation explains how to pass parameters to a reporter on the commandline:
-reporter The extended configuration for a custom report listener. Similar to the -listener option, except that it allows the
configuration of JavaBeans-style properties on the reporter instance.
Example: -reporter
com.test.MyReporter:methodFilter=insert,enableFiltering=true You
can have as many occurences of this option, one for each reporter that
needs to be added.
So it seems I should be able to call testng with -reporter com.my.reporter:key1=value1,key2=value2
but WHERE do I get the values passed in.
I've looked at the XMLReporter provided by testng, and it has a private final XMLReporterConfig config = new XMLReporterConfig(); line, but I can't find out how the config is ever populated.
Magic, that's how it's done :-) It appears it looks for instance variables on your class that implements IReporter with the same name. It does need a stronger type than Object or def though it seems. Here's an example.
class MyReporter implements IReporter {
int foo; //<-- populated when instantiated
#Override
void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) {
println "foo = ${foo}"
}
}
And then to execute it:
testng ... -reporter 'full.path.to.MyReporter:foo=42'
Related
I am having problems to decorate the final class "DocumentGenerator" (in vendor/shopware/core/Checkout/Document/Service/DocumentGenerator.php) and overwrite the "generate" function inside of it.
I tried to decorate it the usual way, but an error is thrown because the "DocumentController" class excepts the original class and not my decorated one?
Argument 2 passed to Shopware\Core\Checkout\Document\DocumentGeneratorController::__construct() must be an instance of Shopware\Core\Checkout\Document\Service\DocumentGenerator
Its also not possible to extend from the class in my decorated class, because the "DocumentGenerator" is a final class.
My goal is to execute additional code, after an order document is generated. Previously I successfully used to decorate the "DocumentService" Class, but its marked as deprecated and shouldnt be used anymore. Also the "DocumentGenerator" class is used for the new "bulkedit" function for documents as of Version 6.4.14.0
I'm grateful for every tip.
As #j_elfering already wrote it's by design that you should not extend that class and therefore also shouldn't decorate it.
To offer a potential alternative:
Depending on what you want to do after a document has been generated it might be enough to add a subscriber to listen to document.written, check if it was a new document created and then work with the data from the payload for fetching/persisting data depending on that.
public static function getSubscribedEvents()
{
return [
'document.written' => 'onDocumentWritten',
];
}
public function onDocumentWritten(EntityWrittenEvent $event): void
{
foreach ($event->getWriteResults() as $result) {
if ($result->getOperation() !== EntityWriteResult::OPERATION_INSERT) {
// skip if the it's not a new document created
continue;
}
$payload = $result->getPayload();
// do something with the payload
}
}
Probably not what you want to hear but: The service is final in purpose as it is not intended to be decorated.
So the simple answer is you can't. Depending on your use case there may be other ways that don't rely on decoration.
I am testing for methodA() in the class :
class Test{
public String methodA(String str){
...
methodB("s1","s2");
...
}
private String methodB(String s1, String s2){
...
}
}
What I have tried in my test class:
Method methodBReflect = Test.class.getDeclaredMethod("methodB", Test.class,String.class, String.class);
methodBReflect.setAccessible(true);
Test testForSpy=new Test();
Test spyTest=spy(testForSpy);
doReturn("return string").when(spyTest..)... // <-- What should be done here?
//methodBReflect.invoke(spyTest, "args1","args2");
P.S: I don't need a solution using powermock as I have some organizational constraints using it.
You shouldn't be testing that method A calls method B. You should test that method A does what method A is supposed to do - that is, it gives the correct output for whatever input you give it. Your test shouldn't care whether method A works by calling method B, or by doing all its processing inline.
Therefore, there's no need to mock or stub anything. Your tests will consist of a bunch of calls to method A, along with verification that the output is what you expect.
You only need to use Mockito (or some other mocking framework) when you're testing a class that interacts with another class entirely; not when the class under test interacts with itself.
I'm trying to use Test NG with Groovy. I implemented a simple test class, but whenever I try to run it I get the following error:
No tests found for given includes: [tests.OTP.get]
Here is what the tests.OTP class looks like:
class OTP{
public static Logger log = LogManager.getLogger(HomePage.class.getName())
String environment = 'qatesting'
String number = '0769878787'
#Test
def get(){
// SoapuiOTP s = new SoapuiOTP(environment,number)
// s.getOTP()
log.info("hello")
Assert.assertEquals(0,System.getProperty("SOAPUI_OTP"))
log.info System.getProperty('SOAPUI_OTP')
}
}
I use the play button (IntelliJ) next to the def get() to run the test but i get the same error on class level. Please assist, I've tried invaliding my cache and restarting. I have looked at TestNG No tests found. Nothing was run and
TestNG - no tests were found, but it didn't help.
You need to replace def with void in the method annotated with #Test. As the documentation says:
Test methods are annotated with #Test. Methods annotated with #Test that happen to return a value will be ignored, unless you set allow-return-values to true in your testng.xml:
<test allow-return-values="true">
Source: https://testng.org/doc/documentation-main.html#test-methods
The def return type compiles to Object, not void, so TestNG ignores this method by default.
This misconception is not TestNG specific and can be done in JUnit as well: Running Groovy test cases with JUnit 5
I have a scripting system where depending on where the script is executed you have access to different variables. I also want to have inferred types for a type of Auto-Completion for the script editor.
But when the types are inferred during the compile phase, I have no way of giving a Binding which explains to the compilation phase what types those dynamic variables have.
I have currently solved this by:
Not compiling the code with either #TypeChecked nor #CompileStatic but later manually running a subclassed StaticCompilationVisitor on the dynamically typed codebase and manually filling in the StaticTypesMarker.INFERRED_TYPE inside visitVariableExpression() for the dynamic variables that I know exists.
However, this seems like the wrong way to go about it, and I would actually like to work with the VariableScope instead. But it seems to be under rough lockdown inside the VariableScopeVisitor, so it's difficult to pop in a CustomVariableScope that dynamically does the lookups. I have managed to do this with reflection, replacing the VariableScopeVisitor inside CompilationUnit and currentScope and such inside VaribleScopeVisitor. It works, but I don't like working against hard-coded private field names.
This might be a long-winded way of asking: Is there an official way of handling a situation of static typing with dynamic variables? I cannot do this by setting scriptBaseClass for reasons too complex to explain here.
If the question is unclear, please tell me and I'll try to edit in better explanations.
The answer was to add a GroovyTypeCheckingExtensionSupport to a StaticTypeCheckingVisitor and then use visitClass on the first ClassNode of the CompilationUnit.
final ClassNode classNode = this.compilationUnit.getFirstClassNode();
final StaticCompilationVisitor visitor = new StaticCompilationVisitor(this.sourceUnit, classNode);
visitor.addTypeCheckingExtension(new MyGroovyTypeCheckingExtensionSupport(visitor, this.compilationUnit));
visitor.visitClass(classNode);
visitor.performSecondPass();
And create something like the class below:
private static class MyGroovyTypeCheckingExtensionSupport extends GroovyTypeCheckingExtensionSupport {
private static final ClassNode CLASSNODE_OBJECT = ClassHelper.make(Object.class);
public MyGroovyTypeCheckingExtensionSupport(StaticTypeCheckingVisitor typeCheckingVisitor, CompilationUnit compilationUnit) {
super(typeCheckingVisitor, "", compilationUnit);
}
#Override
public boolean handleUnresolvedVariableExpression(VariableExpression vexp) {
final ClassNode type = this.getType(vexp);
if (type == null || type.equals(CLASSNODE_OBJECT)) {
if (vextp.getName().equals("something")) {
this.storeType(vexp, ClassHelper.make(SomeClass.class));
return true;
}
}
return false;
}
}
Is it possible to intercept all the methods called in a application? I'd like to do something with them, and then let them execute. I tried to override this behaviour in Object.metaClass.invokeMethod, but it doesn't seem to work.
Is this doable?
Have you looked at Groovy AOP? There's very little documentation, but it allows you to define pointcuts and advice in a conceptually similar way as for AspectJ. Have a look at the unit tests for some more examples
The example below will match all calls to all woven types and apply the advice before proceeding:
// aspect MyAspect
class MyAspect {
static aspect = {
//match all calls to all calls to all types in all packages
def pc = pcall("*.*.*")
//apply around advice to the matched calls
around(pc) { ctx ->
println ctx.args[0]
println ctx.args.length
return proceed(ctx.args)
}
}
}
// class T
class T {
def test() {
println "hello"
}
}
// Script starts here
weave MyAspect.class
new T().test()
unweave MyAspect.class
First of all, overriding Object.metaClass.invokeMethod doesn't work because when Groovy tries to resolve a method call for a type X, it checks the metaClass of X, but not the metaClass of its parent class(es). For example, the following code will print "method intValue intercepted"
Integer.metaClass.invokeMethod = {def name, def args ->
System.out.println("method $name intercepted")
}
6.intValue()
// Reset the metaClass
Integer.metaClass = null
But this code will not:
Object.metaClass.invokeMethod = {def name, def args ->
System.out.println("method $name intercepted")
}
6.intValue()
// Reset the metaClass
Object.metaClass = null
Your question was "Is it possible to intercept all the methods called in a application?", but could you be a bit more precise about whether you want to:
Intercept calls to Groovy methods, Java methods, or both
Intercept calls to only your Groovy/Java methods or also intercept calls to Groovy/Java library classes
For example, if you only want to intercept calls to your Groovy classes, you could change your classes to implement GroovyInterceptable. This ensures that invokeMethod() is invoked for every method called on those classes. If the nature of the interception (i.e. the stuff you want to do before/after invoking the called method) is the same for all classes, you could define invokeMethod() in a separate class and use #Mixin to apply it to all your classes.
Alternatively, if you also want to intercept calls to Java classes, you should check out the DelegatingMetaClass.