I've been doing some work with sling models for a project and in the process created a couple of custom injectors. Everything seems to work great when implemented (used in AEM). However, when I'm testing the custom injectors are not getting run.
Here's an example of what I currently have set up
In MyModel
#Inheritable
#CustomAnnotation("foo")
private String _foo
In test (tests using wcm.io mocking Libraries)
#Rule
AemContext context = new AemContext(ResourceResolverType.RESOURCERESOLVER_MOCK);
//required by the injector
#Mock
InheritanceService _inheritanceService;
#Mock
InheritableInjector _inheritanceInjector;
#Before
public void setup() {
context.registerService(InheritanceService.class, _inheritanceService);
context.registerService(InheritableInjector.class, _inheritanceInjector);
context.addModelsForPackage("com.package.example.models");
//use this resource in tests to adaptTo(MyModel.class)
_resource = context.load().json("myJson.json", "/myPath");
}
... tests
The tests compile and run, but the Injector isn't being executed. I know it's registered because when I don't have the Injector's dependent services registered in the context I get an error. When I debug through it, none of the breakpoints are hit. I'm wondering if I need to also register the "Inheritable" annotation somewhere or if anyone just has any general information on how I can get the custom injector to execute.
thank you
I was able to figure out my error. So the important thing to remember about Sling Model Injectors is that they are just OSGI services (something I completely let myself get away from).
So just treating them like normal services and then remembering to annotate the Injector with #InjectMocks was what I needed to do in order to fix the error.
The following now works great.
#Mock
InheritanceService _inheritanceService; //injector dependency
#InjectMocks
InheritanceInjector _inheritanceInjector;
#Before
public void setup() {
context.registerService(InheritanceService.class, _inheritanceService);
context.registerService(InheritableInjector.class, _inheritanceInjector);
}
hopefully that helps anyone that might run into the issue. If anyone can make this answer better please feel free to reply/edit.
Related
I am testing a Cordova plugin in Java/Android and I need to initialize my Plugin class and set some state before I run my Tests.
#Before
public void beforeEach() throws Exception {
System.out.println("Creating new Instance ");
PowerMockito.mockStatic(Helpers.class);
PowerMockito.when(Helpers.canUseStorage(any(), any())).thenReturn(true);
MyLogger myLoggerMock = PowerMockito.mock(MyLogger.class);
PowerMockito.doNothing().when(myLoggerMock, "log", anyString());
PowerMockito.whenNew(MyLogger.class).withAnyArguments().thenReturn(myLoggerMock);
this.sut = spy(new FilePicker());
PowerMockito.doNothing().when(this.sut).pick(any(), any());
}
I want to create a Test Suite / Java Class per public function, but I do not want to repeat that code every time.
Is there a way to share that before each between test suites? I have found ClassRule but I think I do not do what I need (or I am understanding it wrong... I am really new in Java)
In Typescript we can share beforeEachfunctions with several suites, and each suite can have their own beforeEach
One possible ways is using inheritance:
Make all test classes extend from one "parent test" class and define a #Before in a parent class.
So it will be called automatically for all the subclasses:
public class ParentTest {
#Before
public void doInitialization() {
....
}
}
public class Test1Class extends ParentClass {
#Test
public void fooTest() {
// doInitialization will be executed before this method
}
#Test
public void barTest() {
// doInitialization will be executed before this method as well
}
}
Two notes:
Note 1
In the code you use sut (subject under test) - this obviously should not be in the parent's doInitialization method, so its possible that Test1Class will also have methods annotated with #Before (read here for information about ordering and so forth)
Then the `sut gets initialized with Spy which is frankly weird IMHO, the Subject Under Test should be a real class that you wrote, but that's beyond the scope of the question, just mentioning it because it can point on mistake.
Note 2
I'm writing it in an an attempt to help because you've said that you're new in Java, this is not strictly related to your question...
While this approach works in general you should be really cautious with PowerMockito. I'm not a PowerMockito expert and try to avoid this type of mocks in my code but in a nutshell the way it manipulates the byte code can clash with other tools. From your code: you can refactor the HelperUtils to be non-static and thus avoid PowerMocking in favor of regular mocking which is faster and much more safe.
As for the Logging - usually you can compromise on it in unit test, if you're using slf4j library you can config it to use "no-op" log for tests, like sending all the logging messages into "nothing", and not-seeing them in the console.
I am fairly new to Cucumber. I was experimenting with it by just creating few test features when I noticed the difference when running a single feature vs running the whole suite (from the IntelliJ).
I noticed that when I run single feature it runs using the cucumber-jvm option and in this case, the CucumberConfig(the blank class to define the runner and cucumber options) and the Runner is not utilized. However, when I run the whole suite it runs as a JUnit test and obviously, in this case, the Config class and the runner comes into the picture.
I confirmed this with the following sample code:
#RunWith(CustomRunner.class)
#CucumberOptions()
public class CucumberConfig {
#BeforeClass
public static void beforeClass()
{
System.out.println("This is run before Once: ");
}
#AfterClass
public static void afterClass()
{
System.out.println("This is run after Once: ");
}
}
CustomRunner
public class CustomRunner extends Cucumber {
public CustomRunner(Class clazz) throws InitializationError, IOException {
super(clazz);
System.out.println("I am in the custom runner.");
}
}
Also, I understand that while running as cucumber-junit we can't pass specific feature to run as in cucumber-jvm. Correct me if I am wrong.
My doubt is, is this the default behavior or am I doing something wrong. And, if this is default how can I make cucumber to always use the Config file.
I'll appreciate if someone can provide some insight on this.
When you're using IntelliJ IDEA to run the tests, IDEA will use cucumber.api.Main to run the tests. As such it will ignore CucumberConfig neither will it run #BeforeClass nor #AfterClass, these are only used by the JUnit runner.
I need to execute some code before the #Before method of each unit test is executed. The problem is that I also need to know which test (the name is sufficient) will be executed afterwards.
I can either use AspectJ or Java Agents with bytecode manipulation to achieve this. Also the solution should work for tests where there is no #Before annotation present.
Any ideas?
EDIT: I can't modify the unit tests themselves, as I'm developing a framework for executing tests of other projects
You might want to look into the TestName rule in JUnit:
http://junit.org/junit4/javadoc/4.12/org/junit/rules/TestName.html
About the ordering, a solution could be to define a super class for your tests and put a #Before in there, as #Before methods in super classes are run before those in sub classes.
If you want to write a Java agent and you are not bound to Javassist or AspectJ, have a look at Byte Buddy for doing so. You can add the code in the MyAdvice class to any method annotated with #Test given that the type name ends with Test (as an example) by:
public class MyAgent {
public static void premain(String arg, Instrumentation inst) {
new AgentBuilder.Default()
.type(nameEndsWith("Test"))
.transform((type, cl, builder) -> builder.visit(Advice
.to(MyAdvice.class)
.on(isAnnotatedWith(Test.class)))
.installOn(instrumentation);
}
}
class MyAdvice {
#Advice.OnMethodEnter
static void enter() {
System.out.println("foo");
}
}
Just bundle the above code to a Javaagent with the proper manifest code and register it before running. If you are running on a JDK, you can also attach the agent programmatically using the byte-buddy-agent project.
I am new to Junit testing, would like to test a private method within a class.But it causing visibility problems.how can i test a private method or protected method using Junit.Or can i test a logic within a constructor with Junit??
Simply do it like this:
private someMethod() {}
public someMethodVisibleToAll() {
someMethod();
}
It's not a good idea to hide complex logic in private methods without any access to test it, try to make methods idempotent (without side effects).
In case of legacy code use Powermock, but first try to refactor to code above, if it's not possible than you Powermock as last emergency break.
Just notice: Protected methods are testbable if you use convention that JUnit test has same package name e.g
code src/main/java
package my.package.first
in JUnit folder src/main/test
package my.package.first
than all your protected methods are available to test
Update:
There should always be a way to test private methods indirectly through public methods or protected which uses or includes using of private methods which are cases for testing. If this isn't true and you are not dependent on legacy or third party code, than it's an alert that something is wrong with class design.
I was trying to mock final class(AnyFinalClass.java) in junit using JDave in eclipse.
public void setUp() throws Exception {
Mockery mockery = new Mockery() {{
setImposteriser(ClassImposteriser.INSTANCE);
}};
AnyFinalClass any = mockery.mock(AnyFinalClass.class);
}
I am trying to use jdave-unfinalizer-1.1.jar as javaagent but didnt had any success. I tried multiple things but getting following exception
java.lang.IllegalArgumentException: Cannot subclass final class class AnyFinalClass
at net.sf.cglib.proxy.Enhancer.generateClass(Enhancer.java:446)
at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
Can someone who has already tried jdave unfinalizer give me exact step how to make it work on eclipse.
I set following in eclipse.ini file but got the problem
-Xbootclasspath/a:lC:\WS\JunitTesting\jars\asm-3.0.jar
-javaagent:C:\WS\JunitTesting\jars\jdave-unfinalizer-1.1.jar
While running executing the junit, I gave vm argument as
javaagent:C:\WS\JunitTesting\jars\jdave-unfinalizer-1.1.jar
I am not sure what will be the code. jdave is not having the code and its site is pointing to some other site which is not working. Please correct my code or provide your same working code.
Any help is highly appreciated.
from Enhancer.java line 446:
if (TypeUtils.isFinal(sc.getModifiers()))
throw new IllegalArgumentException("Cannot subclass final class " + sc);
I have not worked with JDave but with another mocking frameworks and the only one that allows to mock a final class was powermock
Look also here
In order to get unfinalizer running you have to put -javaagent:path_to_unfinalizer/jdave-unfinalizer-1.1.jar in the VM arguments of the run configuration of the test.
I also had to include several dependencies of jdave-unfinalizer in the classpath of the project from which the tests ar being launched. These are, taken from the maven definitions of jdave:
jdave-core 1.1
cglib-nodep 2.1_3
objenesis 1.0
asm 3.0
asm-commons 3.0
asm-tree 3.0