I have this code for testing :
private static final Integer documentSetId = 1143;
private static final Integer dsLifeCycleStateId = 1;
private static final String dsLifecycleState = "CVS_CREATED";
CVBusiness cvBusinessTest;
DocumentService documentService;
DocumentSetRepository documentSetRepository;
private DocumentSet documentSet;
private DSLifeCycleState dsLifeCycleState;
#Before
public void setUp(){
cvBusinessTest = new CVBusinessImpl();
documentService = mock(DocumentService.class);
documentSetRepository = mock(DocumentSetRepository.class);
documentSet = new DocumentSet();
dsLifeCycleState = new DSLifeCycleState();
documentSet.setActive(true);
documentSet.setDocumentSetId(documentSetId);
documentSet.setMarkedForTranslation(false);
dsLifeCycleState.setDsLifeCycleStateId(dsLifeCycleStateId);
dsLifeCycleState.setLabel(dsLifecycleState);
documentSet.setDsLifeCycleState(dsLifeCycleState);
when(documentService.getDocumentSetById(documentSetId)).thenReturn(documentSet);
when(documentService.updateDocumentSet(documentSet)).thenReturn(documentSet);
when(documentSetRepository.findOne(documentSetId)).thenReturn(documentSet);
}
#Test
public void markedForTranslationTest() {
boolean retValue = true;
DocumentSet docSet = documentService.getDocumentSetById(documentSetId);
dsLifeCycleState = docSet.getDsLifeCycleState();
if (dsLifeCycleState.getLabel().equals(LifeCycleStateEnum.CVS_CREATED.message()) && docSet.isActive() && !docSet.isMarkedForTranslation() && ((docSet.getfDR() == null) || docSet.getfDR().equals(""))){
documentSet.setMarkedForTranslation(true);
retValue = documentService.updateDocumentSet(documentSet) != null;
}
// retValue = cvBusinessTest.markedForTranslation(documentSetId);
assertTrue(retValue);
}
and when i run Junit, it finished with errors:
java.lang null pointer exception.
Which error points the method bellow
DocumentSet documentSet = documentService.getDocumentSetById(id)
which is in CVBusiness package extended by CVBusinessImpl.
My question is why documentService in CVBusinessImpl throws Null exception?
Thanks!
Maybe you missed to use Spring in your Test? How the documentService is injected?
Add #RunWith(SpringJUnit4ClassRunner.class) to your test class to enable Spring in the test. If you use autowire that should be all. You may also need a #ContextConfiguration annotation to your test and/or add #Resource to the members to be injected.
In your setup, you create your class to test:
cvBusinessTest = new CVBusinessImpl();
and one of the services it requires:
documentService = mock(DocumentService.class);
but you never wire them together. So when your CVBusinessImpl implementation calls:
DocumentSet documentSet = documentService.getDocumentSetById(id)
documentService is still null.
You should wire your objects before testing, either through using a Spring test runner or through setting that field. Something in your setup method like:
cvBusinessTest.setDocumentService(documentService);
Related
When trying to write test case for applicationContext.getBean(classname). Getting null pointer exception.
Below is the Java class
#Service
#Slf4j
public class MyClassName {
#Autowired
ServiceOne serviceOne;
#Autowired
ApplicationContext applicationContext;
public getCitizenData(String mobileNumber) {
CitizenDataService citizenDataService = applicationContext.getBean(CitizenDataService.class, mobileNumber);
log.info("Getting Data");
return citizenDataService.searchMethod(mobileNumber)
// While debugging test file citizenDataService is coming as Null Hence getting Null Pointer exception
.flatMap(.............
)
Test File
class MyClassNameTest {
private MyClassName mockMyClassName;
#BeforeEach
void setUp() {
mockMyClassName = new MyClassName();
mockMyClassName.serviceOne = mock(ServiceOne.class);
mockMyClassName.applicationContext = mock(ApplicationContext.class);
//mockMyClassName.applicationContext.getAutowireCapableBeanFactory();
}
#Test
void testGetCitizenData() {
// Setup
// Configure ApplicationContext.getBean(...).
final CitizenDataService citizenDataService = new CitizenDataService("mobileNumber");
when(mockMyClassName.applicationContext.getBean(CitizenDataService.class, "args"))
.thenReturn(citizenDataService);
final result = mockMyClassName.getCitizenData("mobileNumber");
// While debugging this citizenDataService is coming as Null Hence getting Null Pointer exception
How to write test case for this ?
It is because you stub the incorrect arguments on the getBean() on the mocked ApplicationContext . When a method on a mock is called but there are no matching stubbed arguments , it will return either null or an empty collection , or 0 for an int/Integer and false for a boolean/Boolean by default . So in you case NULL CitizenDataService is returned.
Changing the following should fix your problem :
when(mockMyClassName.applicationContext.getBean(CitizenDataService.class, "mobileNumber"))
.thenReturn(citizenDataService);
Another way is not to mock the ApplicationContext but use spring test to really start up the spring container which include the beans there are required for the test case :
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = {MyClassName.class,ServiceOne.class,CitizenDataService.class})
public class MyClassNameTest {
#Autowired
private MyClassName myClassName
#Test
void testGetCitizenData() {
}
}
This will be slower than the plain Mockito approach because it needs more time to start up the spring container and also require you to manage what beans to be included in the context.
For me , I would refactor your class such that it does not require to autowire ApplicationContext into it and then write a plain Mockito test. It is not a good practise to get the bean from the ApplicationContext manually which will make your class coupled to the spring framework codes.
I don't recommend mocking the application context. There are simply too many methods with similar arguments that it is difficult to mock the correct ones. Instead, use one of the readily available implementations written specifically for the use in tests, such as StaticApplicationContext.
class MyClassNameTest {
private MyClassName mockMyClassName;
private ApplicationContext appCtx;
#BeforeEach
void setUp() {
mockMyClassName = new MyClassName();
mockMyClassName.serviceOne = mock(ServiceOne.class);
this.appCtx = new StaticApplicationContext();
}
#Test
void testGetCitizenData() {
appctx.registerBean(CitizenDataService.class, () -> new CitizenDataService("mobileNumber"));
final result = mockMyClassName.getCitizenData("mobileNumber");
I'm trying to create a unittest for the method below (myHostClient), but I'm having some problems with it:
MyClass.java
import com.abc.def.ServiceBuilder
public class MyClass {
#Value("${materialLocation}")
private String materialValue
private static final SERVICEBUILDER = new ServiceBuilder()
#Bean public MyHostServiceClient myHostClient(
#Value(${qualifier_one}) final String qualiferOne,
#Value(${use_service}) final boolean useService) {
if(useService) {
return SERVICEBUILDER
.remote(MyHostServiceClient.class)
.withConfig(qualifierOne)
.withCall(new CallerAttach(Caller.retro(defaultStrategy())), // Error Line2 Here
new SigningVisitor(new CredentialsProvider(materialValue))),
call -> call.doSomeStuff(StuffObject.getStuffInstance()))
.makeClient();
}
#Bean DefaultStrategy<Object> defaultStrategy() {
final int valueA = 1;
final int valueB = 2;
return new DoSomeThingsBuilder()
.retry(valueA)
.doSomethingElse(valueB)
.create();
}
}
And here is my latest unsuccessful attempt at writing a unittest for it:
MyClassTest.java
import org.mockito.Mock
import static org.mockito.Mockito.times
public class MyClassTest {
#Mock
private SERVICEBUILDER serviceBuilder;
private MyClass myClass;
private String qualifierOne = "pass"
#BeforeEach
void setUp() {
myClass = new MyClass();
}
#Test
public void test_myHostClient() {
boolean useService = true;
final MyHostServiceClient result = myclass.myHostClient(qualifierOne, useService); // Error Line1 here
verify(serviceBuilder, times(1));
}
}
I have been trying to mock SERVICEBUILDER and verify that the mocked object is called one time but no luck so far. Right now I'm getting this error:
IllegalArgumentException: Material Name cannot be null
And it points to these lines in my code.
In the Test:
final MyHostServiceClient result = myclass.myHostClient(qualifierOne, useService);
Which points to this line in the module:
.withCall(new CallerAttach(Caller.retro(defaultStrategy())),
Anyone know how I can fix my unittest or write a working one from scratch?
I would say the design of MyClass is quite wrong because it looks like a Spring configuration but apparently it's not. If it is really supposed to be a configuration then I wouldn't even test it like this because it would rather be an integration test. Of course, even in integration tests you can mock dependencies. But the test itself would run differently and you would have to spin up a suitable Spring context, etc.
So given the above, I would rather make MyClass some sort of MyHostServiceClientFactory with removing all of the Spring annotations and then fix the following problems in your code.
SERVICEBUILDER is hardcoded.
SERVICEBUILDER is static final and its value is hardcoded into MyClass. You will not be able to reassign that field with the mocked version. It can still be final but not static then and it's better to use dependency injection here by passing the value through the MyClass constructor.
SERVICEBUILDER will still be not mocked even if you fix the above.
To really mock SERVICEBUILDER by using the #Mock annotation in the test you should enable Mockito annotations.
If you are using JUnit5 then you should annotate your test class like this:
#ExtendWith(MockitoExtension.class)
public class MyClassTest {
...
}
If you are stuck with JUnit4 then you should use another combination:
#RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
...
}
Once you've done that the SERVICEBUILDER will be mocked but now you will have to configure the behaviour of that mock, like what is going to be returned by the SERVICEBUILDER methods. I can see 4 methods in total, namely remote, withConfig, withCall, and makeClient. You will have to do Mockito's when/thenReturn configurations.
MyClass.materialValue is null.
But even when your mock will be properly configured you will still encounter the original IllegalArgumentException: Material Name cannot be null. This is because MyClass.materialValue will still be null and looks like CredentialsProvider cannot accept that. As I can see, that field is supposed to be injected by Spring using the #Value annotation, but remember this class no longer contains anything from Spring. As in problem 1, you have to pass the value through the MyClass constructor.
Once all of these problems are solved you can introduce a thin Spring configuration like MyHostServiceClientConfiguration (or whatever name suits you) that would serve as a provider of necessary properties/dependencies for MyHostServiceClientFactory (existing MyClass) and then this factory can provide you with a MyHostServiceClient bean through a method like MyHostServiceClientConfiguration#myHostServiceClient annotated with #Bean.
Conceptually your MyHostServiceClientFactory will look like this:
public class MyHostServiceClientFactory {
private final String materialValue;
private final ServiceBuilder serviceBuilder;
public MyHostServiceClientFactory(String materialValue, ServiceBuilder serviceBuilder) {
this.materialValue = materialValue;
this.serviceBuilder = serviceBuilder;
}
public MyHostServiceClient myHostClient(String qualiferOne, boolean useService) {
if(useService) {
return serviceBuilder
.remote(MyHostServiceClient.class)
.withConfig(qualifierOne)
.withCall(new CallerAttach(Caller.retro(defaultStrategy())), // Error Line2 Here
new SigningVisitor(new CredentialsProvider(materialValue))),
call -> call.doSomeStuff(StuffObject.getStuffInstance()))
.makeClient();
}
// can also be injected as a dependency rather than being hardcoded
DefaultStrategy<Object> defaultStrategy() {
final int valueA = 1;
final int valueB = 2;
return new DoSomeThingsBuilder()
.retry(valueA)
.doSomethingElse(valueB)
.create();
}
}
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
I am facing a weird issue where my unit tests are failing/succeeding on retrying. I previously wrote unit test case for 2 classes in my package and when I wrote the unit test cases for third class the test cases for the other two classes also start failing due to errors listed below
Errors in generated test Report:
Error 1
Cannot instantiate #InjectMocks field named 'chunkedSnapshot' of type 'class
com.XXXX.YYY.lambda.ChunkedSnapshot'. You haven't provided the instance at field declaration so
I tried to construct the instance. However the constructor or the initialization block threw an
exception : null
Error 2
Problems adding Mockito listener. Listener of type 'MismatchReportingTestListener' has already
been added and not removed. It indicates that previous listener was not removed according to the
API. When you add a listener, don't forget to remove the listener afterwards: Mockito.framework().removeListener(myListener); For more information, see the javadoc for
RedundantListenerException class.
Some error in console which I feel might be relevant
[junit] Cannot instantiate #InjectMocks field named 'chunkedSnapshot' of type 'class com.XXXX.YYYY.lambda.ChunkedSnapshot'.
[junit] You haven't provided the instance at field declaration so I tried to construct the instance.
[junit] However the constructor or the initialization block threw an exception : null
The weird thing is that the test cases sometimes succeed, sometimes do not.
I will paste down the initialization piece of the third class and unit test class for same which is causing this issue
#Log4j2
public class ChunkedSnapshot implements RequestHandler<String, String> {
private final AmazonAthena amazonAthena;
private AthenaQueryExecutor athenaQueryExecutor;
private final String snapshotDate;
private final String tableName;
private final String databaseName;
private final String currentTable;
private final String externalS3Location;
private final String workGroup;
private String buyableDate;
public ChunkedSnapshot() {
this(new LambdaConfiguration(System.getenv()));
}
public ChunkedSnapshot(LambdaConfiguration lambdaConfiguration) {
this(lambdaConfiguration.getAmazonAthena());
}
public ChunkedSnapshot(AmazonAthena amazonAthena) {
this.amazonAthena = amazonAthena;
ConfigInitializer.initializeConfig();
snapshotDate = LocalDate.now().toString();
tableName = AppConfig.findString(ATHENA_MAIN_TABLE);
databaseName = AppConfig.findString(ATHENA_DATABASE);
workGroup = AppConfig.findString(ATHENA_WORKGROUP);
currentTable = AppConfig.findString(CURRENT_TABLE);
externalS3Location = AppConfig.findString(TABLE_S3_LOCATION);
athenaQueryExecutor = new AthenaQueryExecutor();
}
#Override
public String handleRequest(String event, Context context) {
//some content here
}...more content
Unit Test
#RunWith(MockitoJUnitRunner.class)
public class ChunkedSnapshotTests extends AbstractTestCase {
#Mock
Context mockContext;
#Mock
AthenaQueryExecutor mockAthenaQueryExecutor;
#Mock
AmazonAthena mockAmazonAthena;
#InjectMocks
ChunkedSnapshot chunkedSnapshot;
List<Row> rowList;
List<Datum> datumList;
String event = "some test event";
#Before
public void setup() throws InterruptedException {
rowList = new ArrayList<>();
datumList = new ArrayList<>();
Row row = new Row();
Datum datum1 = new Datum();
datum1.setVarCharValue("some val");
Datum datum2 = new Datum();
datum2.setVarCharValue("some val");
datumList.add(datum1);
datumList.add(datum2);
row.setData(datumList);
rowList.add(row);
when(mockAthenaQueryExecutor.processResultRows(any(), any())).thenReturn(rowList);
}
#Test
public void testHandleRequest() {
chunkedSnapshot.handleRequest(event, mockContext);
}
..... more content
I feel there must be some problem in the initialization of the InjectMocks since this is the first class out of previous test classes which is using the inject mocks.Any help would be appreciated.
I'm trying to test a method. And in this method, a new Object is instancied, but I don't want it, otherwise other class will be tested.
How I tell to mockito dont intanciate it?
#Component
#EnableScheduling
public class VerificadorDeNovasAssinaturas {
private DocuSign docuSign;
private ApiClient apiClient;
#Autowired
private DocuSignProperties docuSignProperties;
public EnvelopesInformation verificaNovasAssinaturas() throws Exception {
this.docuSign = new DocuSign(docuSignProperties); // I don't want mockito instanciate DocuSign
this.apiClient = docuSign.getApiClient();
this.apiClient.addDefaultHeader("Authorization", "Bearer " + docuSign.getoAuthToken().getAccessToken());
And my test class:
#SpringBootTest
#RunWith(SpringRunner.class)
#ActiveProfiles("test")
public class VerificadorDeNovasAssinaturasTest {
#InjectMocks
private VerificadorDeNovasAssinaturas verificador;
private DocuSignProperties docuSignProperties;
private ApiClient apiClient;
private UserInfo userInfo;
private OAuthToken oAuthToken;
#Mock
private DocuSign docuSign;
#Before
public void initialize() throws Exception {
docuSignProperties = new DocuSignProperties();
docuSignProperties.setBaseUrl("https://demo.docusign.net/restapi");
docuSignProperties.setBasePath("/restapi");
setApiClientConfigurations();
when(docuSign.getApiClient()).thenReturn(this.apiClient);
when(docuSign.getoAuthToken()).thenReturn(this.oAuthToken);
...}
private void setApiClientConfigurations() throws Exception {
this.apiClient = new ApiClient(this.docuSignProperties.getBaseUrl());
this.oAuthToken = getOAuth();
... }
#Test
public void testaVerificacaoDeNovasAssinaturas() throws Exception {
EnvelopesInformation results = verificador.verificaNovasAssinaturas();
assertNotNull(results);
}
I don't want mockito instanciate a new DocuSign, because this is not the reason of the test. There is some way do ignore this step?
Well, Mockito can not change something if your code( Code to be tested, Which you intend to) does something, However you can mock it so that it does not create a new object (rather have your "Mocked Object"), so that you can verify something against the expected behavior.
In your code if you change few lines , you can achieve what you want, like -
Create a DocuSignService class and there you create this new object in say some - getDocuSign method. Then your code looks something like below -
#Autowired
private DocuSignService docuSignService ;
this.docuSign = new DocuSign(docuSignProperties); // This is what you have
this.docuSign = this.docuSignService.getDocuSign() ; // This is new code
Now in your test case -
#Mock
DocuSignService docuSignService ;
#Mock
private DocuSign docuSign;
//.
//.
Mockito.when(this.docuSignService.getDocuSign()).thenReturn(docuSign);
Now you have control on this object.
I resolved it using powerMockito.
DocuSign docuSign = PowerMockito.mock(DocuSign.class);
PowerMockito.whenNew(DocuSign.class).withAnyArguments().thenReturn(docuSign);