Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.
Better Exception Testing in ICE with J-Unit
Better JUNIT Testing
In many developing software applications (including ICE), unit testing has become a vital role in developing reliable, safer, and more robust products. JUNIT is one of the tools that can be used to run unit and integration tests for Java-based applications in test-driven development. Below is an example of utilizing better methods for developing unit tests for handling Exceptions on tested objects with the testing tool.
Here is a sample exception try/catch statement within a JUnit test:
//A class that tests the operation //StringToIntegerUtility.customStrToInt(String number) @Test public void checkStringToInteger() { //Local declaration int number; String number = "Not a number"; boolean expectedFail = false; //Setup class StringToIntegerUtility utility = new StringToIntegerUtility(); //Call operation with try/catch statement try { number = utility.customStrToInt(number); } catch (NumberFormatException e) { //We expect this to happen expectedFail = true; } //Test is valid if it failed assertTrue(expectedFail); }
When the utility operation is called, there has to be a try/catch statement. Try/catch statements can clutter code and confuse some forms of unit testing. What can be done is to separate these specific exception unit tests into their own methods and have JUNIT check the exceptions. Below is a better way to handle the exceptions in a JUNIT test.
//A class that tests the operation //StringToIntegerUtility.customStrToInt(String number) @Test(expected=java.lang.NumberFormatException.class) public void checkStringToInteger() throws NumberFormatException { //Local declaration int number; String number = "Not a number"; //Setup class StringToIntegerUtility utility = new StringToIntegerUtility(); //Call operation, and this operation should //throw an exception. number = utility.customStrToInt(number); }
This method cuts down on some of the more excessive try/catch statements in unit testing. It also helps to modularize the codebase in unit testing by separating out the exception cases from other tests. The expected statement catches the exception when it is thrown. Nevertheless, there are some limitations to this method. For example, when the exception is thrown, the testing ends in that method. Thus, if one were to need to write more expansive tests that utilize many exceptions, there would need to be an individual method for each exception. Secondly, this can pose a problem for identifying messages in exceptions for generic Exception handling or classes with multiple types of references. The second issue can be resolved by using the thrown.expect(class) and thrown.expectMessage(String) from the JUnit API. These types of calls are declared within the method and not annotated.
Locations of Exceptions
There are many areas in ICE where native and customized exceptions are thrown and caught within the applications. Many of them are required by overloaded applications, while others are created to catch specific errors in ICE. Below is a list of the operations that throw and/or catch exceptions within ICE's general architecture. It will also mention if the error prints out a stack trace or not. If it does, it will mention whether or not the operation is handled within the method. Note that just printing a stack trace does not constitute an operation as "being handled". Returning false on a boolean method for a failed initialization of another method because of a try/catch statement is an example of "handling" an issue.
This is a table for exceptions caught within each method.
ICEClient | ||||
---|---|---|---|---|
Class | Method | Exception | Prints a stack trace? | Handles error? |
EclipseFormWidget | display() | PartInitException | Yes | No |
EclipseTestEditor | display() | PartInitException | Yes | No |
ICEFormEditor | addPages() | PartInitException | Yes | No |
ICEMatrixComponentSectionPart | modify() | NumberFormatException | No | No |
ICEGeometryPage | createFormContent() | PartInitException | Yes | No |
GeometryApplication | commit() | ClassCastException | No | No |
RealSpinner | validateText() | NumberFormatException | No | Yes |
ShapeMaterial | applyShape() | NumberFormatException | No | No |
Itemprocessor | run() | InterruptedException | Yes | No |
ICECore | ||||
---|---|---|---|---|
Class | Method | Exception | Prints a stack trace? | Handles error? |
BasicAuthSecuredContext | failedAuthorization() | IOException | Yes | No |
BasicAuthSecuredContext | getResource() | MalformedURLException | No | Yes |
BasicAuthSecuredContext | handleSecurity() | LoginException | Yes | Yes |
ICECore | start() | ServletException, NamespaceException, IOException | All yes | All no |
ICECore | setLocation() | CoreException | Yes | Yes |
ICECore | loadDefaultAreaItems() | IOException, CoreException | All yes | Yes, No |
SimpleLogin | login() | IOException, UnsupportedLoginException | All yes | All yes |
ICEDataStructures | ||||
---|---|---|---|---|
Class | Method | Exception | Prints a stack trace? | Handles error? |
DataComponent, Entry, Form, MasterDetailsComponent | loadFromXML() | NullPointerException, JAXBException, IOException | All yes | All yes |
MasterDetailsPair, MatrixComponent, TableComponent | loadFromXML() | NullPointerException, JAXBException, IOException | All yes | All yes |
ComplexShape, GeometryComponent, PrimitiveShape | loadFromXML() | NullPointerException, JAXBException, IOException | All yes | All yes |
Transformation, ICEObject, ICEResource | loadFromXML() | NullPointerException, JAXBException, IOException | All yes | All yes |
Entry | setValue() | NumberFormatException | No | Yes |
AbstractShape | getProperty() | IndexOutOfBoundsException | No | Yes |
ICEObject | persistToXML() | NullPointerException, JAXBException, IOException | Yes | No |
ICEResource | setContents() | NullPointerException | No | Yes |
ICEItem | ||||
---|---|---|---|---|
Class | Method | Exception | Prints a stack trace? | Handles error? |
Item | process() | CoreException | Yes | No |
Item | loadFromXML() | IOException, JAXBException, IOException | Yes | Yes |
Item | persistToDatabase() | Exception | Yes | Yes |
Item | deleteFromDatabase() | Exception | Yes | Yes |
Item | updateToDatabase() | Exception | Yes | Yes |
Item | loadFromDatabase() | Exception | Yes | Yes |
JobLaunchAction | createSession() | JschException | Yes | No |
JobLaunchAction | BufferedWriter() | IOException | Yes | No |
JobLaunchAction | isLocalHost() | UknownHostException | Yes | No |
JobLaunchAction | launchLocally() | IOException | Yes | Yes |
JobLaunchAction | launchRemotely() | InterruptedException, JschException, FileNotFoundException, SftpException | All yes | All no |
TaggedOutputWriterAction | execute() | IOException | Yes | Yes |
JobLauncher | createOutputFiles() | CoreException, IOException | All yes | All no |
JobLauncher | setupForm() | CoreException | Yes | No |
JobLauncher | loadFromXML() | IOException, JAXBException, NullPointerException | Yes | Yes |
MultiLauncher | run() | InterruptedException | Yes | No |
JobProfile | process() | CoreException | Yes | No |
This is a table for a list of exceptions thrown within each method of each class. Usually when an exception is thrown, an issue is handled in a higher level operation/method. Therefore "handles error" does not apply here.
ICEClient | |||
---|---|---|---|
Class | Method | Exception | Prints a stack trace? |
EntryComposite | EntryComposite() | RuntimeException | No |
ICEDataComponentSectionPart | ICEDataComponentSectionPart() | RuntimeException | No |
ICEFormEditor | Init() | RuntimeException | No |
ICEMatrixComponentSectionPart | ICEMatrixComponentSectionPart() | RuntimeException | No |
ICESectionPage | ICESectionPage() | RuntimeException | No |
ICETableComponentSectionPart | ICETableComponentSectionPart() | RuntimeException | No |
ShapeTransient | read() | IOException | No |
ShapeTransient | write() | IOException | No |
Tube | read() | IOException | No |
Tube | write() | IOException | No |
ICECore | |||
---|---|---|---|
Class | Method | Exception | Prints a stack trace? |
BasicAuthSecuredContext | handleSecurity() | IOException | No |
BasicAuthSecuredContext | login() | IOException, UnsupportedCallbackException, LoginException | No |
SimpleLogin | abort() | LoginException | No |
SimpleLogin | commit() | LoginException | No |
SimpleLogin | login() | LoginException | No |
ICECoreIApplication | start() | Exception | No |
ICEDataStructures | |||
---|---|---|---|
Class | Method | Exception | Prints a stack trace? |
Form | addComponent() | RuntimeException | No |
PainfullySimpleEntry | loadFromPSFBlock() | IOException | No |
PainfullySimpleForm | loadComponents() | IOException | No |
PainfullySimpleForm | loadEntries() | IOException | No |
ICEJAXBManipulator | read() | JAXBException, IOException | No |
ICEJAXBManipulator | write() | JAXBException, IOException | No |
ICEResource | ICEResource() | IOException | No |
ICEResource | setContents() | IOException, NullPointerException | No |
ICEItem | |||
---|---|---|---|
Class | Method | Exception | Prints a stack trace? |
Item | Item() | RuntimeException | No |
Item | loadFromPSF() | IOException | No |
SerializedItemBuilder | SerilaizedItemBuilder() | IOException | No |
References
http://weblogs.java.net/blog/johnsmart/archive/2009/09/27/testing-exceptions-junit-47
http://kentbeck.github.com/junit/javadoc/4.10/org/junit/rules/ExpectedException.html