Sterling OMS How to use JUnit and Code Coverage
In our previous post we saw how to use HTTP Java Tester for testing code.
Sterling OMS How to use JUnit and Code Coverage ?
In this post we are going to see how JUnit Testing and Code Coverage going to help developers, writing 100 % bug free code with simple example.
What is JUnit Testing (Google Definition) ?
JUnit is a unit testing framework for the Java programming language. Used for test driven development.
Website: http://junit.org/junit5/
How to install JUnit jar ?
Download following jar files and add part of Eclipse Build Path
- junit-4.12
- hamcrest-core-1.3
What is Code Coverage (Google Definition) ?
Code Coverage is a measurement of how many lines/blocks/arcs of your code are executed while the automated tests are running.
Website : http://www.eclemma.org/
How to install Code Coverage (eclemma/Jacoco) ?
- Open Eclipse IDE
- Go to Help menu — Eclipse Marketplace
- Type “EclEmma”
- Install EclEmma plugin
- Restart Eclipse
Requirement Given to OMS Developer: Need to write Dynamic Condition for validating customer level payment process required flag based on the Enterprise code input passed.
Input to Dynamic Condition : <Order EnterpriseCode=”Matrix” />
Here is some possible scenarios input can come.
# | Input | Description | Expected Value |
1 | <Order EnterpriseCode=”Matrix” /> | Valid Input | True/False Based on configuration |
2 | <Order EnterpriseCode=”” /> | Blank Enterprise Code | FALSE |
3 | <Order OrganizationCode=”” /> | Looking for Enterprise Code | FALSE |
4 | <Organization /> | Invalid root element | FALSE |
5 | Empty Input | FALSE | |
6 | <Order EnterpriseCd=”” /> | Invalid attribute | FALSE |
7 | <Order /> | Attribute missing | FALSE |
Developer writing implementation logic !!!
- Create New java file PaymentProcessRequiredDynamicCondition.java
- Above class should implement YCPDynamicCondition (interface)
- And override method evaluateCondition()
public boolean evaluateCondition(YFSEnvironment env, String name, Map mapData, String xmlData) { }
- Build and deploy the code
- Create new Service
- Configure the Dynamic condition
- Add DB component (YFS_EXPORT)
- Call the Newly Service from API tester and complete testing
Question to OMS developer ?
- Are we testing all the scenario given above ? (Different possible input)
- How to keep note of all the scenario tested ?
- If any mistake in code; again perform build and deploy. How much time wasted for build and deployment ?
- How to make sure any change performed later point of time, not having impact to existing code/logic ?
Let’s see how do it in the new JUnit Way !!!
One Time Setup
- Open resources\yifclient.properties and modify following values
- yif.yif.httpapi.userid=admin
- yif.httpapi.password=password
- yif.httpapi.url=http://localhost:7001/smcfs/interop/InteropHttpServlet
- Open (Create new if not available) properties\customer_overrides.properties and create following entry
- yif.yif.httpapi.userid=admin
- yif.httpapi.password=password
- yif.httpapi.url=http://localhost:7001/smcfs/interop/InteropHttpServlet
- Run command from bin folder deployer.cmd -t resourcejar
- Run build using below command
buildear.cmd -Dappserver=weblogic -Dwarfiles=smcfs,sbc -Dearfile=smcfs.ear -Dnowebservice=true -Ddevmode=true -Dnodocear=true -Dwls-10=true create-ear
- Deploy the newly created ear file.
- Add resources.jar (jar\platform\9_4) and properties.jar (tmp\smcfs) into eclipse build path
Note: yifclient.properties file gets added into resources.jar; customer_overrides.properties gets added into properties.jar
Coding and Execution
- Create folder and file Structure as shown below
- Write new file PaymentProcessRequiredDynamicCondition.java
package com.oms94.validation; import java.util.Map; import javax.xml.transform.TransformerException; import org.w3c.dom.Document; import com.oms94.util.XMLUtil; import com.yantra.interop.japi.YIFApi; import com.yantra.interop.japi.YIFClientFactory; import com.yantra.ycp.japi.YCPDynamicCondition; import com.yantra.yfc.dom.YFCDocument; import com.yantra.yfc.dom.YFCElement; import com.yantra.yfs.japi.YFSEnvironment; public class PaymentProcessRequiredDynamicCondition implements YCPDynamicCondition { protected YIFApi api = null; @Override public boolean evaluateCondition(YFSEnvironment env, String name, Map mapData, String xmlData) { YFCDocument xml = null; String enterpriseCode = null; try { if(xmlData == null || xmlData.isEmpty()) { return false; } xml = YFCDocument.getDocumentFor(xmlData); // get EnterpriseCode from input XML enterpriseCode = xml.getDocumentElement().getAttribute("EnterpriseCode"); return isPaymentProcessRequired(env, enterpriseCode); } catch (Exception ex) { throw new RuntimeException("PaymentProcessRequiredDynamicCondition failed due to ..."); } } private boolean isPaymentProcessRequired(YFSEnvironment env, String enterpriseCd) throws Exception { Document outputDoc = getApi().invoke(env, "getOrganizationList", getOrganizationInput(enterpriseCd)); return paymentProcessRequired(outputDoc); } private Document getOrganizationInput(String orgCode) { YFCElement organization = YFCDocument.createDocument("Organization") .getDocumentElement(); organization.setAttribute("OrganizationCode", orgCode); return organization.getOwnerDocument().getDocument(); } private boolean paymentProcessRequired(Document documentResult) throws TransformerException { String paymentProcessRequired = XMLUtil.getValue(documentResult, "OrganizationList/Organization/@PaymentProcessingReqd"); if("Y".equalsIgnoreCase(paymentProcessRequired)) { return true; } return false; } protected YIFApi getApi() throws Exception { api = YIFClientFactory.getInstance().getApi(); return api; } }
- Write new file PaymentProcessRequiredDynamicConditionTest.java
package com.oms94.validation; import java.util.HashMap; import javax.xml.transform.TransformerException; import org.junit.Test; import com.oms94.test.BaseTestCase; import com.oms94.validation.PaymentProcessRequiredDynamicCondition; public class PaymentProcessRequiredDynamicConditionTest extends BaseTestCase { @Test public void paymentProcessRequiredPositiveCondition() throws TransformerException { PaymentProcessRequiredDynamicCondition paymentDynaCondition = new PaymentProcessRequiredDynamicCondition(); org.junit.Assert.assertTrue("", paymentDynaCondition.evaluateCondition(env, "getOrganizationList", new HashMap<String,String>(), "<Order EnterpriseCode=\"Matrix\" />")); } @Test public void paymentProcessRequiredNegitiveCondition1() throws TransformerException { PaymentProcessRequiredDynamicCondition paymentDynaCondition = new PaymentProcessRequiredDynamicCondition(); org.junit.Assert.assertFalse("", paymentDynaCondition.evaluateCondition(env, "getOrganizationList", new HashMap<String,String>(), "<Order EnterpriseCode=\"\" />")); } @Test public void paymentProcessRequiredNegitiveCondition2() throws TransformerException { PaymentProcessRequiredDynamicCondition paymentDynaCondition = new PaymentProcessRequiredDynamicCondition(); org.junit.Assert.assertFalse("", paymentDynaCondition.evaluateCondition(env, "getOrganizationList", new HashMap<String,String>(), "<Order EnterpriseCode=\"ABC\" />")); } @Test public void paymentProcessRequiredNegitiveCondition3() throws TransformerException { PaymentProcessRequiredDynamicCondition paymentDynaCondition = new PaymentProcessRequiredDynamicCondition(); org.junit.Assert.assertFalse("", paymentDynaCondition.evaluateCondition(env, "getOrganizationList", new HashMap<String,String>(), "<Order />")); } @Test public void paymentProcessRequiredNegitiveCondition4() throws TransformerException { PaymentProcessRequiredDynamicCondition paymentDynaCondition = new PaymentProcessRequiredDynamicCondition(); org.junit.Assert.assertFalse("", paymentDynaCondition.evaluateCondition(env, "getOrganizationList", new HashMap<String,String>(), "<OrderList />")); } @Test public void paymentProcessRequiredNegitiveCondition5() throws TransformerException { PaymentProcessRequiredDynamicCondition paymentDynaCondition = new PaymentProcessRequiredDynamicCondition(); org.junit.Assert.assertFalse("", paymentDynaCondition.evaluateCondition(env, "getOrganizationList", new HashMap<String,String>(), "")); } @Test public void paymentProcessRequiredNegitiveCondition6() throws TransformerException { PaymentProcessRequiredDynamicCondition paymentDynaCondition = new PaymentProcessRequiredDynamicCondition(); org.junit.Assert.assertFalse("", paymentDynaCondition.evaluateCondition(env, "getOrganizationList", new HashMap<String,String>(), null)); } }
- Add new file BaseTestCase.java (One time)
package com.oms94.test; import java.util.ResourceBundle; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.junit.BeforeClass; import org.w3c.dom.Document; import org.w3c.dom.Element; import com.yantra.interop.japi.YIFApi; import com.yantra.interop.japi.YIFClientFactory; import com.yantra.yfc.dom.YFCDocument; import com.yantra.yfc.dom.YFCElement; import com.yantra.yfc.rmi.YFCRemoteManager; import com.yantra.yfs.japi.YFSEnvironment; public class BaseTestCase { protected static YIFApi api = null; protected static YFSEnvironment env = null; protected static DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); protected static DocumentBuilder docBuilder = null; protected static String sessionId = null; @BeforeClass public static void setUp() { System.out.println("BeforeClass"); try { System.setProperty("yfs.logall", "N"); System.setProperty("file.encoding", "UTF-8"); System.setProperty("vendor", "shell"); System.setProperty("vendorFile", "/servers.properties"); System.setProperty("sci.opsproxy.disable","Y"); System.setProperty("sci.naming.provider.url","t3://localhost:7001"); System.setProperty("wufdevmode","true"); System.setProperty("uiExtensibilityMode","true"); init(); }catch(Exception e) { System.out.println(e); e.printStackTrace(); } } protected YFSEnvironment getEnv() throws Exception { return env; } protected YIFApi getApi() throws Exception { return api; } protected static void init() throws Exception { if (env != null) { return; } ResourceBundle rb = ResourceBundle.getBundle("resources/yifclient"); if(rb == null) { System.out.println("Resource file not loaded correctly"); return; }else { System.out.println("loaded keys:" + rb.keySet()); } String userId = rb.getString("yif.httpapi.userid"); String pwd = rb.getString("yif.httpapi.password"); String url = rb.getString("yif.httpapi.url"); System.out.println("url: " + url + " as user " + userId); try { api = YIFClientFactory.getInstance().getApi(); YFCRemoteManager.setIsLocalInvocation(false); //use http docFactory.setNamespaceAware(true); docBuilder = docFactory.newDocumentBuilder(); Document environmentDoc = docBuilder.newDocument(); Element envElement = environmentDoc.createElement("YFSEnvironment"); envElement.setAttribute("userId", userId); envElement.setAttribute("progId", userId); environmentDoc.appendChild(envElement); env = api.createEnvironment(environmentDoc); YFCDocument loginInput = getLoginInputRequest(userId, pwd); Document loginDoc = api.invoke(env, "login", loginInput.getDocument()); sessionId = loginDoc.getDocumentElement().getAttribute("UserToken"); if(sessionId != null && !sessionId.isEmpty()) { env.setTokenID(sessionId); }else { System.out.println("Not able to get the session details"); } }catch(Exception e) { System.out.println("Error"); e.printStackTrace(); } System.out.println("Login Success"); } private static YFCDocument getLoginInputRequest(String userId, String pwd) { YFCDocument loginInput = YFCDocument.createDocument("Login"); YFCElement loginElement = loginInput.getDocumentElement(); loginElement.setAttribute("LoginID", userId); loginElement.setAttribute("Password", pwd); return loginInput; } }
- Add new file XMLUtil.java (One time)
package com.oms94.util; import java.io.StringWriter; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.apache.xpath.XPathAPI; import org.w3c.dom.Document; import org.w3c.dom.Node; public class XMLUtil { public static String getStringFromDocument(Document doc) { try { DOMSource domSource = new DOMSource(doc); StringWriter writer = new StringWriter(); StreamResult result = new StreamResult(writer); TransformerFactory tf = TransformerFactory.newInstance(); Transformer transformer = tf.newTransformer(); transformer.transform(domSource, result); return writer.toString(); } catch(TransformerException ex) { return null; } } /** * @param node * @param xpath * @return * @throws TransformerException */ public static String getValue(Node node, String xpath) throws TransformerException { if (null == node || null == xpath || 0 == xpath.trim().length()) { return null; } Node ret = null; ret = XPathAPI.selectSingleNode(node, xpath); return ret == null ? null : ret.getNodeValue(); } }
- Go to PaymentProcessRequiredDynamicConditionTest.java file and right click “Coverage As”
- Validate the JUnit Results in J-Unit Tab
- Validate the Code Coverage details
- Pink color shows – Code which is never executed by test case.
- Green color shows – Original code been invoked part of at-lease one of the test case.
So as a developer our goal should be increase the code coverage percentage % by writing more test cases. It might look like writing one additional Java file for J-Unit testing. Might take bit more time for development but in the long run with just one click will be able to test the code without build and deployment.
This is just sample; We should override the request and response XML values using MockIto (Avoid calling the API/Service).
Answer from OMS developer for previous questions ?
- Are we testing all the scenario given above ? (Different possible input) Answer: Yes we did test all possible inputs
- How to keep note of all the scenario tested ? Answer: Showing All J-Unit passed is the way to show all scenario passed
- If any mistake in code; again perform build and deploy. How much time wasted for build and deployment ? Answer: Can change the code N number for times without need for build and deployment
- How to make sure any change performed later point of time, not having impact to existing code/logic ? Answer: We can run the J-Unit test case any point time when some code change happened.
Note : Similar can be implemented using JMeter. If any one has idea please share how JUnit and Code coverage can be implemented using JMeter.
Please share your feedback on this post. If you have any query please comment below or email as directly at support@activekite.com.
Happy Learning !!!!
Register with us to get more OMS learning updates
Click here to read OMS Interview Questions
if you receive below error while running Junit test
Error :
java.lang.OutOfMemoryError: PermGen space
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.security.SecureClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.defineClass(Unknown Source)
Solution :
Make below configuration in eclipse
1) click on the link “Open launch configuration”
2) switch to the Arguments tab
3) add -XX:MaxPermSize=512m in the VM arguments text area
Error : Resource file not loaded correctly
Solution: check resources.jar file added to build path
Error : MissingResourceException with particular property key and value
Solution : Make sure yifclient.properties has particular property key and value. Build and deployment completed once. Right JAR file added to build path.
Thanks a lot for covering this useful topic very nice way..
Thanks Ravi
use yif.httpapi.userid=admin instead of yif.yif.httpapi.userid=admin in yifclient.properties
Lekha
if we want to override any value available part of properties file, we should use customer_overrides.properties. Its not good idea to change value directly in properties file For example yifclient.properties file.
When we override value in customer_overrides.properties should give yif.yif.httpapi.userid=admin so syntax is
PROPERTY_FILE_NAME_PREFIX.PROPERTY_NAME=PROPERTY_VALUE
Search in google “IBM OMS Properties Guide filetype:pdf” read first link
Hope you agree !!!
Hi Team,
Getting below exception, while trying to create Environment.
An error occurred reading vendorFile: /servers.properties
classpath: /servers.properties
Attempting to retry
An error occurred reading vendorFile: /servers.properties
classpath: /servers.properties
Attempting to retry
An error occurred reading vendorFile: /servers.properties
classpath: /servers.properties
java.io.FileNotFoundException: classpath: /servers.properties
at com.sterlingcommerce.woodstock.util.frame.Manager.newInputStream(Manager.java:155)
at com.sterlingcommerce.woodstock.util.frame.Manager.newInputStream(Manager.java:147)
at com.sterlingcommerce.woodstock.util.frame.Manager.doStaticInit(Manager.java:233)
at com.sterlingcommerce.woodstock.util.frame.Manager.(Manager.java:171)
at com.yantra.yfc.dblayer.YFCEntity.(YFCEntity.java:73)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:90)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:55)
at java.lang.reflect.Method.invoke(Method.java:508)
at com.yantra.ycp.core.YCPValidatingEntityApiImpl.(YCPValidatingEntityApiImpl.java:55)
at com.yantra.ycp.core.YCPValidatingEntityApiImpl.(YCPValidatingEntityApiImpl.java:41)
at com.yantra.ycp.core.YCPEntityApi.(YCPEntityApi.java:198)
at com.yantra.yfs.japi.util.YFSInitializer.initializeEntityApi(YFSInitializer.java:180)
at com.yantra.yfs.japi.util.YFSInitializer.initialize(YFSInitializer.java:88)
at com.yantra.interop.client.YIFClientFactoryImpl.doCommonInitializations(YIFClientFactoryImpl.java:88)
at com.yantra.interop.client.YIFClientFactoryImpl.getApi(YIFClientFactoryImpl.java:297)
at com.yantra.interop.client.YIFClientFactoryImpl.getAutoApiClient(YIFClientFactoryImpl.java:343)
at com.yantra.interop.client.YIFClientFactoryImpl.getApi(YIFClientFactoryImpl.java:318)
at com.yantra.interop.client.YIFClientFactoryImpl.getApi(YIFClientFactoryImpl.java:243)
at com.yantra.interop.client.YIFClientFactoryImpl.getApi(YIFClientFactoryImpl.java:238)
at com.yantra.interop.client.YIFClientFactoryImpl.getApi(YIFClientFactoryImpl.java:232)
at com.sdg.common.util.CreateEnvironment.init(CreateEnvironment.java:81)
at com.sdg.common.util.CreateEnvironment.assignProperties(CreateEnvironment.java:41)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:90)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:55)
at java.lang.reflect.Method.invoke(Method.java:508)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at org.junit.vintage.engine.execution.RunnerExecutor.execute(RunnerExecutor.java:39)
at org.junit.vintage.engine.VintageTestEngine$$Lambda$161.00000000117C8620.accept(Unknown Source)
at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:195)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:204)
at java.util.Iterator.forEachRemaining(Iterator.java:127)
at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1812)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:523)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:513)
at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:162)
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:185)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:245)
at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:429)
at org.junit.vintage.engine.VintageTestEngine.executeAllChildren(VintageTestEngine.java:79)
at org.junit.vintage.engine.VintageTestEngine.execute(VintageTestEngine.java:70)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:170)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:154)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:90)
at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)
WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
You did not correctly specify a vendorFile system property,
in order for me to run correctly, you need to specify a vendorFile.
For example:
java -DvendorFile=/path/to/vendor.properties
WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
com.sterlingcommerce.woodstock.util.frame will not work without this parameter.
We assume you are trying with weblogic server and getting this error during application server start ?
if yes can you please try below
set SAVE_JAVA_OPTIONS=%JAVA_OPTIONS% -Dfile.encoding=UTF-8 -Dsci.opsproxy.disable=Y -Dvendor=shell -DvendorFile=/servers.properties
Dsci.naming.provider.url=t3://localhost:7001 -Dwufdevmode=true -DuiExtensibilityMode=true
Hope this helps !!!