Difference between revisions of "Unit Test Framework"
imported>Aeric m (Text replace - 'Designer > Classes' to 'File:GearIcon.png > Developer Resources > Classes') |
imported>Aeric |
||
(3 intermediate revisions by the same user not shown) | |||
Line 13: | Line 13: | ||
Finally, to make it all work, you need an ''automated'' test harness that will run your tests and make it possible to quickly zero in on any that failed. That is the goal of the Unit Test Framework. | Finally, to make it all work, you need an ''automated'' test harness that will run your tests and make it possible to quickly zero in on any that failed. That is the goal of the Unit Test Framework. | ||
{{Important|<br>Changes made to a record in a unit test ''do not persist''. That way, the results you get do not depend on the order in which you run them. That's great for proper unit tests, but there are times when you need to try things out programatically, and then inspect the results interactively. The way to do that is to create an [[Event Rule]] that invokes the method. | |||
:''Learn more:'' [[Java Debugging Tips#Invoking Methods]]}} | |||
==Creating Unit Tests== | ==Creating Unit Tests== | ||
Line 18: | Line 21: | ||
{{:Creating Unit Tests}} | {{:Creating Unit Tests}} | ||
==Sample Tests== | |||
Here's a class with a few sample tests, to help you get started: | |||
:<syntaxhighlight lang="java" enclose="div"> | |||
package com.platform.acme.demo; | |||
import com.platform.api.*; | |||
public class MyClass | |||
{ | |||
@TestMethod | |||
public void test1_string() throws Exception | |||
{ | |||
String expect = "yes"; | |||
String actual = "yes"; | |||
RunTest.assertEquals(expect, actual); | |||
} | |||
@TestMethod | |||
public void test2_int() throws Exception | |||
{ | |||
// Convert the ints to strings | |||
String expect = ""+1; | |||
String actual = ""+1; | |||
RunTest.assertEquals(expect, actual); | |||
} | |||
@TestMethod | |||
public void test3_boolean() throws Exception | |||
{ | |||
// Convert the booleans to strings | |||
String expect = ""+true; | |||
String actual = ""+true; | |||
RunTest.assertEquals(expect, actual); | |||
} | |||
@TestMethod | |||
public void test4_fail() throws Exception | |||
{ | |||
String expect = "yes"; | |||
String actual = "no"; | |||
RunTest.assertEquals(expect, actual); | |||
} | |||
} | |||
</syntaxhighlight> | |||
==Running Unit Tests on a Class== | ==Running Unit Tests on a Class== | ||
===To run tests for a class=== | ===To run tests for a class=== | ||
# Go to the list of [[Classes]] | # Go to the list of [[Classes]] | ||
#: '''[[File:GearIcon.png]] > Developer Resources > Classes''' | #: '''[[File:GearIcon.png]] > Customization > Developer Resources > Classes''' | ||
# Select a class | # Select a class | ||
# Click '''Run Tests''' | # Click '''Run Tests''' | ||
Line 34: | Line 82: | ||
===To run tests for all classes=== | ===To run tests for all classes=== | ||
# Go to the list of [[Classes]] | # Go to the list of [[Classes]] | ||
#: '''[[File:GearIcon.png]] > Developer Resources > Classes''' | #: '''[[File:GearIcon.png]] > Customization > Developer Resources > Classes''' | ||
# Click '''Run All Tests''' | # Click '''Run All Tests''' | ||
#: Tests are run for all classes. The results page appears. | #: Tests are run for all classes. The results page appears. |
Latest revision as of 20:44, 29 July 2014
In the AgileApps Cloud platform, the Unit Test Framework makes it possible to define tests in your classes, and then run them on one class at a time, or on all of your classes at once.
About Unit Testing
Unit Testing is the key that unlocks the door to programming nirvana. As your suite of unit tests grow, bugs that would have been exceptionally deep suddenly become extraordinarily shallow--because some test, somewhere, surfaces the "violation of expectations" that occurs when a method deep in the belly of the code returns an unexpected value. Without a comprehensive test suite, you find yourself laboriously tracing your way down a chain of calls to find it. But with a comprehensive test suite, debugging frenzies are a thing of the past; Because one of your unit tests inevitably takes you right to the source of the problem, where there are only a few lines of code to debug.
In addition, as Martin Fowler points out so well, a comprehensive suite of unit tests makes it possible to refactor with impunity. If that new feature you want to add requires drastic reorganization of the code, no worries. Your comprehensive test suite makes sure that after refactoring, everything works in exactly the same way it did before.
- Note:
Fowler's particular genius lay in pointing out that you what seems like a very large refactoring can be broken down into a number of much smaller steps. So you do a small amount of refactoring, and then run the test suite to make sure everything is still working. If everything succeeds, you do a bit more of the refactoring. If it isn't working, you fix things, or even back out your changes and start over. At every stage of the process, everything works exactly the way it did before. By the end of the process, it's possible to have made very large changes, and at the same time know that you haven't broken anything.
Of course, you only get a comprehensive test suite if you write your tests as you go along, side by side with your code. In fact, it's a generally considered a good idea to write tests before you write your code. That way, (a) You're guaranteed to have them and (b) You know with certainty when your code is working the way you expect it to.
In a way, unit tests also provide highly detailed, totally accurate documentation of your APIs. In some shops, in fact, you're not even allowed to commit code to the shared repository unless it is accompanied by the tests which describe the behavior, and at the same guarantee compliance with the description.
Finally, to make it all work, you need an automated test harness that will run your tests and make it possible to quickly zero in on any that failed. That is the goal of the Unit Test Framework.
Important:
Changes made to a record in a unit test do not persist. That way, the results you get do not depend on the order in which you run them. That's great for proper unit tests, but there are times when you need to try things out programatically, and then inspect the results interactively. The way to do that is to create an Event Rule that invokes the method.- Learn more: Java Debugging Tips#Invoking Methods
Creating Unit Tests
Any method in a Java class can be a test method, as long as it is tagged with the @TestMethod annotation. Within the test method, use assert statements like this one to compare expected results to actual results: RunTest.assertEquals(expected, actual).
Here's a template for a test method:
- <syntaxhighlight lang="java" enclose="div">
/**
* javadoc comment */
@TestMethod public void testSomeBehavior() throws Exception {
String expect = "It's working!"; String actual = someBehavior(); // Invoke the method you're testing
RunTest.assertEquals(expect, actual);
} </syntaxhighlight>
See also: Code Sample:Test of Search using Java API
- Considerations
- A single test method can contain multiple assertions.
- Each successful assertion adds to the success count and the count of total tests.
- A test method may contain no assertions at all. In that case, it runs to completion, but the test is not counted as a success.
- A test may fail either because an exception occurs, or because an assertion fails.
- In either case, the message is recorded. (For an exception, a stack trace is also recorded.)
- Whether an assertion succeeds or fails, the method continues running. It is only interrupted by an exception.
- If multiple assertions fail, all of the failure messages are reported.
- If one or more assertions fail, and then an exception occurs, all of the messages are reported, along with the exception.
- The test method (testSomeBehavior, above) must be public. If it isn't, an IllegalAccessException occurs when the @TestMethod annotation causes the Unit Test Framework to attempt execution.
- The RunTest.assertEquals() method takes Strings as arguments (and only Strings).
Important:
When running tests, the UI is never affected. So your tests always run to completion without pausing for user interactions, regardless of the code contained in the executed methods. These cases in particular are executed without having any visible effect in the UI:- Functions.showMessage - Ordinarily brings up a dialog.
- setTargetPage in a controller - Ordinarily specifies the next page the user will see.
- Any request sent from a controller - Ordinarily specifies the controller code or JSP page that will be visited next.
Sample Tests
Here's a class with a few sample tests, to help you get started:
- <syntaxhighlight lang="java" enclose="div">
package com.platform.acme.demo;
import com.platform.api.*;
public class MyClass {
@TestMethod public void test1_string() throws Exception { String expect = "yes"; String actual = "yes"; RunTest.assertEquals(expect, actual); }
@TestMethod public void test2_int() throws Exception { // Convert the ints to strings String expect = ""+1; String actual = ""+1; RunTest.assertEquals(expect, actual); }
@TestMethod public void test3_boolean() throws Exception { // Convert the booleans to strings String expect = ""+true; String actual = ""+true; RunTest.assertEquals(expect, actual); }
@TestMethod public void test4_fail() throws Exception { String expect = "yes"; String actual = "no"; RunTest.assertEquals(expect, actual); }
} </syntaxhighlight>
Running Unit Tests on a Class
To run tests for a class
- Go to the list of Classes
- Select a class
- Click Run Tests
- All tests defined in the class are run. The results page appears.
Test Results
This page shows the results of running the tests defined in a class.
Summary
- Tested Class - The class that was tested.
- Tests Run - The total number of test methods that were executed.
- Test Failures - Tests that failed, either because an assertion failed or because an exception occurred.
- Tests Succeeded - A count of the number of assertions that succeeded. If a single test method makes 2 assertions, and each succeeds, it counts as 2 successful tests.
- Total Time (ms) - The total amount of time that was taken to execute the tests, in milliseconds.
Failed Methods
This section shows the tests that failed, either because an exception occurred or because an assertion statement turned out to be false. The error message is displayed in either case. If there was an exception, a stack trace is shown, as well.
Running Unit Tests for All Classes
To run tests for all classes
- Go to the list of Classes
- Click Run All Tests
- Tests are run for all classes. The results page appears.
All Test Results
This page shows the results of running the tests defined in all classes.
Column Headings
- Tested Class - The class that was tested.
- Tests Run - The total number of test methods that were executed.
- Test Failures - Tests that failed, either because an assertion failed or because an exception occurred.
- Tests Succeeded - A count of the number of assertions that succeeded. If a single test method makes 2 assertions, and each succeeds, it counts as 2 successful tests.
- Total Time (ms) - The total amount of time that was taken to execute the tests, in milliseconds.