How do I create a Test Suite at runtime - java

Class A {
#Test
#CustomAnnotation(attrib1 = "foo"; attrib2 = "moo"; attrib3 = "poo")
void methodA(){ }
#Test
#CustomAnnotation(attrib1 = "blahblah"; attrib2 = "flahflah"; attrib3 = "klahklah")
void methodB(){ }
#Test
#CustomAnnotation(attrib1 = "foo"; attrib2 = "flahflah"; attrib3 = "poo")
void methodC(){ }
}
Now, using reflection, my annotation processing class will return me a SET/LIST of methods which match my criteria (say,attrib1="foo") - Method A and method C will satisfy. Now I need to add these to a test suite at runtime and run that.
How can I add them to the test suite?

Have a look at org.junit.runner.JUnitCore. You should be able to specify the set of tests to run (methods that have to be executed as tests) using org.junit.runner.Request: http://junit.sourceforge.net/javadoc/org/junit/runner/JUnitCore.html#run(org.junit.runner.Request)

Related

AEM JUnit java.lang.NullPointerException

I need to create a Junit test for a class in an AEM project and I'm having NullPointerException problems:
I create the ClassTestImpl
#ExtendWith({AemContextExtension.class, MockitoExtension.class})
class TestImpl {
private final AemContext ctx = new AemContext();
#Mock
private Test test;
#Mock
private ModelFactory modelFactory;
#BeforeEach
void setUp() throws Exception {
ctx.addModelsForClasses(TestImpl.class);
ctx.load().json("/com/project/core/models/adobe/TestImplTest.json","/content");
lenient().when(modelFactory.getModelFromWrappedRequest(eq(ctx.request()),
any(Resource.class), eq(Test.class)))
.thenReturn(test);
}
#Test
void testGetText() {
final String expected = "textTEST";
ctx.currentResource("/content/text");
Test test = ctx.request().adaptTo(Test.class);
String actual = test.getText();
assertEquals(expected,actual);
}
and the json structure:
"text": {
"jcr:primaryType": "nt:unstructured",
"sling:resourceType": "project/components/core/title",
"text": "textTEST"
}
}
when i Run test i give that result:
#Test
void testGetText() {
final String expected = "titleTEST";
ctx.currentResource("/content/title");
Title title = ctx.request().adaptTo(Title.class);
-->String actual = title[NullPointerException].getText();<--
assertEquals(expected,actual);
}
It looks like your model is a null reference. You do try to mock it with MockitoExtension but that's largely superfluous, given that you're also using AemContextExtension and it's probably the cause of the issue.
Null pointers aside, this code doesn't even test anything. Everything is mocked, even the Test class which I understand to be the subject under test.
Also, the parameter you're passing to addModelsForClasses looks like the test class (TestImpl) rather than the class of the Sling Model Test.
Instead of relying on Mockito, let the AEM Mocks library set up all the underlying objects by itself and make sure the class you're testing is the real thing, rather than a mock.
#ExtendWith(AemContextExtension.class)
class TestImpl {
private final AemContext ctx = new AemContext();
#BeforeEach
void setUp() throws Exception {
ctx.addModelsForClasses(Test.class); // Give it the Sling Model
ctx.load().json("/com/project/core/models/adobe/TestImplTest.json","/content");
}
#Test
void testGetText() {
final String expected = "textTEST";
ctx.currentResource("/content/text");
Test test = ctx.request().adaptTo(Test.class); // It'll use the actual class, not a mock this way
String actual = test.getText();
assertEquals(expected,actual);
}
}
See
https://sling.apache.org/documentation/development/sling-mock.html#sling-models-1
https://wcm.io/testing/aem-mock/usage-content-loader-builder.html

Is it possible to override #DisabledIfEnvironmentVariable in jUnit 5?

I have a class of jUnit 5 tests that is not allowed to run in the main pipeline (for multiple reasons). In order to disabled those tests in the pipeline but work on a developer machine I introduced #DisabledIfEnvironmentVariable for the test class (and it works great):
#DisabledIfEnvironmentVariable(named = "USER", matches = "(.*jenkins.*|.*tomcat.*)")
#SpringBootTest(classes = {BigApplication.class}, webEnvironment = RANDOM_PORT)
class LongRunningApplicationTest { ... }
How can I override #DisabledIfEnvironmentVariable if I want to run the test class on an occasion?
I tried adding #EnabledIfEnvironmentVariable hoping that it will override #DisabledIfEnvironmentVariable annotation, therefore providing me with a convenient way to run the test in the pipeline on occasion:
#EnabledIfEnvironmentVariable(named = "applicationTest", matches = "true")
#DisabledIfEnvironmentVariable(named = "USER", matches = "(.*jenkins.*|.*tomcat.*)")
#SpringBootTest(classes = {BigApplication.class}, webEnvironment = RANDOM_PORT)
class LongRunningApplicationTest { ... }
However the above approach doesn't work. Is there a way to override #DisabledIf... ?
One solution is to introduce your own conditions using following annotations:
#EnabledIf or #DisabledIf.
#EnabledIf("EnabledIfAnnotationUtils#shouldRun")
class ApplicationTest {
#Test
void renameMe() {
assertThat(false).isTrue();
}
}
Where EnabledIfAnnotationUtils - is external class (in case you have multiple tests under same condition) and #shouldRun - name of static method. Example:
public class EnabledIfAnnotationUtils {
static boolean shouldRun() {
boolean override = getPropertySafely("run-long-tests").equalsIgnoreCase("true");
if(override) return true;
String user = getEnvSafely("USER");
boolean isOnJenkins = user.toLowerCase().contains("jenkins") || user.toLowerCase().contains("tomcat");
return !isOnJenkins;
}
private static String getPropertySafely(String name) {
return "" + System.getProperty(name);
}
private static String getEnvSafely(String name) {
return "" + System.getenv(name);
}
}
Now tests will NOT run on Jenkins unless override parameter passed, example:
mvn test -Drun-long-tests=true

How to conditionally run parameterized tests in JUnit5?

Exactly I mean tag #EnabledIfSystemProperty using with #ParameterizedTest tag.
When I use #EnabledIfSystemProperty with #Test, the test method is being disabled and after tests run it is grayed out on the list (as I expect):
#Test
#EnabledIfSystemProperty(named = "env", matches = "test")
public void test() {
System.out.println("Only for TEST env");
}
Whereas I use #EnabledIfSystemProperty with #ParameterizedTest, the test is green on the list after tests run but it is not actually executed:
#ParameterizedTest
#EnabledIfSystemProperty(named = "env", matches = "test")
#ValueSource(strings = {"testData.json", "testData2.json"})
public void test(String s) {
System.out.println("Only for TEST env");
}
I execute tests from IntelliJ IDEA.
I need the test to be grayed out on the list. Any ideas? Thanks...
You could move the parameterized test to a #Nested test and apply the condition to it:
#Nested
#EnabledIfSystemProperty(named = "env", matches = "test")
class Inner {
#ParameterizedTest
#ValueSource(strings = {"testData.json", "testData2.json"})
public void test(String s) {
System.out.println("Only for TEST env: " + s);
}
}

Test if another method is called from a class using JUnit or Mockito

I have a class like this
public class LoginPresImpl implements LoginAPIInterface.LoginDataListener, LoginAPIInterface.LoginPresenter{
LoginAPIInterface.LoginView loginView;
LoginAPIInterface.LoginDataInteractor loginDataInteractor;
public LoginPresImpl(LoginAPIInterface.LoginView loginView) {
this.loginView = loginView;
loginDataInteractor=new LoginDataModel(this);
}
#Override
public void getLoginUpdateData(String username, String password,String registrationToken) {
loginDataInteractor.getLoginData(username,password,registrationToken);
}
}
I want to test if calling
getLoginUpdateData()
will call the getLoginDate() method of loginDataInteractor.
I have created a test class like this
public class LoginPresImplTest {
LoginAPIInterface.LoginDataInteractor loginDataInteractorMock;
LoginAPIInterface.LoginView loginViewMock;
LoginPresImpl loginPres;
#Before
public void setUp(){
loginDataInteractorMock = Mockito.mock(LoginAPIInterface.LoginDataInteractor.class);
loginViewMock = Mockito.mock(LoginAPIInterface.LoginView.class);
loginPres = Mockito.spy(LoginPresImpl.class);
}
#Test
public void getLoginUpdateData() {
loginPres.getLoginUpdateData("01","","");
verify(loginPres).getLoginUpdateData("01","","");
}
But I don't know how to check if calling
getLoginUpdateData()
will eventually call
loginDataInteractor.getLoginData()
method. How can I test this using JUnit or Mockito.
I want to test if calling
getLoginUpdateData()
will call the getLoginDate() method of loginDataInteractor.
loginDataInteractor is a dependency of the code under test (cut) you showed.
In a UnitTest you only verify the behavior of the cut. You do not verify the behavior of the dependencies. They get their own unit tests.

Test a method which calls another method of the object in mockito

I have an interface, ex:
interface MyService {
void createObj(int id)
void createObjects()
}
I want to test an implementation of the createObjects method, which has body like:
void createObjects() {
...
for (...) {
createObj(someId);
}
}
I have already tested createObj(id):
#Test public void testCreate() {
//given
int id = 123;
DAO mock = mock(DAO.class);
MyService service = new MyServiceImpl(mock);
//when
service.createObj(id);
//verify
verify(mock).create(eq(id));
}
So I don't want to repeat all test cases for it in the test for createObjects.
How can I make sure that another method of the real object was called besides the one I am testing?
Use a spy:
MyService myService = new MyServiceImpl()
MyService spy = spy(myService);
doNothing().when(spy).createObj(anyInt());
// now call spy.createObjects() and verify that spy.createObj() has been called
This is described, like everything else, in the api doc.

Categories