6.10 Unit Test Introduction to Web Design
1. Creating a Unit Test
Unit tests provide valuable feedback by instantiating a small portion of your application and verifying its behavior in three steps: Arrange, Act and Assert. If there are bugs in your code that fail this test, debugging will become much simpler; unit tests are fast enough that they can be run frequently delivering near instantaneous value feedback.
Before creating a unit test, the first step should be creating a test case. As this document serves as the blueprint that testers will follow, it must be clear, precise, and comprehensive. Furthermore, it should adhere to the Single Responsibility Principle which states that every piece of code should have one responsibility – this ensures tests remain straightforward, quick, and dependable.
In the Test Steps field, list all steps required to execute the test. In the Test Data field, provide details regarding what data will be used during testing, while Expected Result indicates your desired outcomes of said tests.
Use the Test Explorer’s Group By button to organize your tests hierarchically, or customize grouping according to your own unique requirements.
2. Creating a Test Class
Test classes are an efficient way of organizing tests for similar pieces of logic. For instance, you might create one test class dedicated to testing functions that insert records in Salesforce, another dedicated to retrieving data from Salesforce, and yet another which checks for specific error messages. Grouping your tests together like this helps ensure complete coverage while making failure easier to pinpoint.
Test classes are defined with a factory method typically called @Test, which turns all public methods of the class into test methods without needing additional TestNG annotations such as @before or @after or class level @isTest annotations. This encourages developers to adhere to the Single Responsibility Principle by not including too many effects in one test that might cause it to fail due to unintended side-effects.
The test class also defines a default runTest() method, which is called when running any test. Individual test methods may override this default to change its behavior – for instance by specifying maxDiff to limit how often messages are sent when an assert method fails, or by creating an IteratorObject[]> and invoking its methods with each element of an iterator object.
3. Creating a Test Method
An effective test method consists of three steps: arrange, act and assert. Arranging involves setting up variables or instantiating objects needed for running the test; acting involves calling out to tested functions to be checked; finally assert is used to check that results match what was expected – in essence keeping test methods short so they’re easier for readers and listeners alike to follow.
Alternatively, use the @subtest() annotation if you want your test method’s context manager to be used by the test runner to provide information during its run, such as adding dots (“.”) as each test runs or supporting running under debugger.
Another great feature of the test runner is its ability to allow you to specify groupings of tests, making it easier to organize similar cases into meaningful clusters. Groupings are created using @beforeMethod and @AfterMethod annotations which allow more sophisticated groups of tests that can be invoked quickly when necessary without needing to recompile your class.
4. Creating a Test Function
Establishing a test function is the cornerstone of creating unit tests. Test functions can either be defined inside a class, or as standalone methods; short test functions help keep tests focused on testing only one small piece of code at a time.
If a test function requires external values from external sources, like data returned by an API, it’s common practice to create a fixture which stores these values. That way, should there be any network outage or other issue which prevents its successful execution, the tests can still run later using this same data. There are various ways of doing this including the requests library which contains methods specifically for keeping response fixtures for later use in tests.
Test variables provide another method for creating test data. A variable is a named value that can be referenced throughout a test case and generated at test runtime by using its value to parse HTTP response headers or bodies, for instance. Local variables tend to be more efficient as their memory consumption occurs only while an entity (test module, test case or action) containing them executes (whereas global variables consume memory until all execution of their suite has finished).
5. Creating a Test Variable
As part of your test execution, variables provide a way to store values and pass data between operations. Variables can be created in either the Variables page of a keyword test or using Set Variable Value operation and come in various types:
Keyword test variables provide the flexibility needed to cover expected and unexpected outcomes of functions or methods in tests, providing you with more robust coverage of any unexpected behaviour within a method or function.
To create a test object, select the class where you would like to add test results, and click Create Test Object. Enter information such as name, type, default value category and description before clicking Finish to add this object to a keyword test or cancel to close out of this dialog without taking any actions.
TestComplete verifies that any value assigned to a variable matches both its type and value type, so as to avoid incompatibilities. For instance, assigning a string value to an integer variable will result in it only holding numbers in decimal format (hexadecimal and octal values are not supported). If it differs significantly, TestComplete attempts to convert it to match its variable’s type.
6. Creating a Test Object
Test objects are classes that contain methods used to perform actions on an application under test. For example, WebButton test objects might provide an “click” method which executes at runtime and clicks its respective button at runtime. Each test object should have a unique name and be stored in its own separate test folder for easy organization of tests by class or action.
This attribute specifies the maximum length of diffs output from assert methods that report differences on failure, defaulting to 80 * 8 characters.
Test objects may exhibit identification properties that vary during a test run or under specific conditions. These properties can be modified manually using SetTOProperty statements or parameterized with Data Table parameters to provide greater flexibility during iterations of testing.
This attribute determines whether custom messages should be appended to standard failure messages generated by assert methods, by default setting it to True; however this setting can be changed for individual test methods if desired. It should only be used if your framework supports shared fixtures.
7. Creating a Test Result
Test results provide stakeholders with an accurate view of testing activities. As part of the testing process, these are essential and should follow a standard template, making review easier for testers. Information included should be succinct and pertinent.
Test Summary Reports provide an overview of test results, failure rate, status of each test case step and any known issues, giving the testing team the information needed to quickly identify potential areas of concern and address them before taking their application Live.
The IDE makes it easy to view individual test results by right-clicking on them and selecting Show Results from the menu, or viewing test suite and case results by navigating directly to their folder in Project Explorer. Furthermore, Track Running Test enables monitoring execution by clicking its icon on Test Runner toolbar – plus Display Inline Statistics provides access to run execution time statistics per suite/case run.