ballerina/test0.0.0
Module overview
This module facilitates developers to write automation tests for ballerina code in a simple manner. It provides a number of capabilities such as configuring setup and cleanup steps in different levels, ordering and grouping of tests, providing value-sets to tests and independence from external functions and endpoints via mocking capabilities.
Annotations
A ballerina testsuite can be implemented using a set of annotations. The available annotations enable executing instructions before and after the testsuite or a single test, organize a set of tests into a group, define data-driven tests, specify an order of execution, disable tests and mocking.
The following example shows a simple testsuite.
1import ballerina/io;2import ballerina/test;34// Before Suite Function5@test:BeforeSuite6function beforeSuiteFunc() {7 io:println("I'm the before suite function!");8}910// Before test function11function beforeFunc() {12 io:println("I'm the before function!");13}1415// Test function16@test:Config {17 before: "beforeFunc",18 after: "afterFunc"19}20function testFunction() {21 io:println("I'm in test function!");22 test:assertTrue(true, msg = "Failed!");23}2425// After test function26function afterFunc() {27 io:println("I'm the after function!");28}2930// After Suite Function31@test:AfterSuite {}32function afterSuiteFunc() {33 io:println("I'm the after suite function!");34}
The following example shows how an individual test can be configured.
1@test:Config{2 enable: false, // default is true3 before: "init",4 after: "cleanup",5 dependsOn: ["test1"],6 dataProvider:"dataGen"7}8function dataProviderTest (int value) returns error? {9 test:assertEquals(value, 1, msg = "value is not correct");10}1112function dataGen() returns (int[][]) {13 return [[1]];14}
Assertions
This module provides a number of assertions in order to verify the expected behaviour of a piece of code. These assertions can be used to decide if the test is passing or failing based on the condition.
Following sample shows how to use assertions in Testerina.
12import ballerina/test;34type Person object {5 public string name = "";6 public int age = 0;7 public Person? parent = ();8 private string email = "default@abc.com";9 string address = "No 20, Palm grove";10 };1112@test:Config{}13function testAssertIntEquals() {14 int answer = 0;15 int a = 5;16 int b = 3;17 answer = intAdd(a, b);18 test:assertEquals(answer, 8, msg = "int values not equal");19}2021@test:Config {}22function testAssertNotEqualsString() {23 string s1 = "abc";24 string s2 = "def";25 test:assertNotEquals(s1, s2, msg = "string values are equal");26}2728@test:Config {}29function testAssertExactEqualsObject() {30 Person p1 = new;31 Person p2 = p1;32 test:assertExactEquals(p1, p2, msg = "Objects are not exactly equal");33}3435@test:Config {}36function testAssertNotExactEqualsObject() {37 Person p1 = new;38 Person p2 = new ();39 test:assertNotExactEquals(p1, p2, msg = "Objects are exactly equal");40}4142@test:Config {}43function testAssertTrue() {44 boolean value = true;45 test:assertTrue(value, msg = "AssertTrue failed");46}4748@test:Config {}49function testAssertFalse() {50 boolean value = false;51 test:assertFalse(value, msg = "AssertFalse failed");52}5354@test:Config {}55function testAssertFail() {56 if (true) {57 return;58 }59 test:assertFail(msg = "AssertFailed");60}6162function intAdd(int a, int b) returns (int) {63 return (a + b);64}
Mocking
The test module provides capabilities to mock a function or an object for unit testing. The mocking features can be used to control the behavior of functions and objects by defining return values or replacing the entire object or function with a user-defined equivalent. This feature will help you to test the Ballerina code independently from other modules and external endpoints.
Function Mocking
Function mocking allows to control the behavior of a function in the module being tested or a function of an imported module.
The annotation @test:Mock {}
is used to declare a MockFunction
object, with details of the name of the function to be mocked, as well as the module name if an import function is being mocked. The module name value of the annotation is optional if the function being mocked is not an import function.
1import ballerina/math;2import ballerina/test;34@test:Mock {5 moduleName : "ballerina/math",6 functionName : "absInt"7}8test:MockFunction mock_absInt = new();910@test:Config {}11public function testFunction() {12 test:when(mock_absInt).thenReturn(100);13 test:assertEquals(math:absInt(-5), 100);14}
Declaring the annotation with this object will create a default mock object in place of the original function. Subsequent to the declaration, the function call should be stubbed using the available mocking features. Different behaviors can be defined for different test cases if required.
Samples
main.bal
1public function intAdd(int a, int b) returns (int) {2 return a + b;3}
test.bal
The following example shows different ways of stubbing a function call.
1@test:Mock { functionName: "intAdd" }2test:MockFunction intAddMockFn = new();34public function mockIntAdd(int x, int y) returns int {5 return x - y;6}78@test:Config {}9public function testMockCall() {10 // stubbing to invoke the created mock function11 test:when(intAddMockFn).call("mockIntAdd");12 test:assertEquals(intAdd(10, 6), 4);1314 // stubbing to return the specified value15 test:when(intAddMockFn).thenReturn(5);16 test:assertEquals(intAdd(10, 4), 5);1718 // stubbing to return a value based on input19 test:when(intAddMockFn).withArguments(20, 14).thenReturn(100);20 test:assertEquals(intAdd(20, 14), 100);21}
Object Mocking
Object mocking enables controlling the values of member variables and the behavior of the member functions of an object. This is vital when working with client objects as the remote functions can be stubbed to return a mock value without having to actually make calls to the remote endpoint.
Mocking of objects can be done in two ways.The available features provide the functionality to substitute the real object with a user-defined mock object or to stub the behavior of required functions.
- Creating a test double (providing an equivalent object in place of the real)
- Stubbing the member function or member variable (specifying the behavior of functions and values of variables)
Creating a test double is suitable when a single mock function/object can be used throughout all tests whereas stubbing is ideal when defining different behaviors for different test cases is required.
Creating a test double
A custom mock object can be defined in place of the real object which should contain the member variables and functions that need to be replaced. The custom object should be made structurally equivalent to the real object via the mocking features in the test module. A runtime exception will be thrown if any of the defined functions or variables is not equivalent to the counterpart of the original object.
main.bal
1http:Client clientEndpoint = new("http://petstore.com");23function getPet(string petId) returns Pet | error {4 http:Response|error result = clientEndpoint->get("/pets?id="+petId);5 if(result is error) {6 return result;7 } else {8 Pet pet = constructPetObj(result);9 return pet;10 }11}
test.bal
1// Mock object definition for http:Client object2public type MockHttpClient client object {3 public remote function get(@untainted string path, public4 http:RequestMessage message = ()) returns http:Response|http:ClientError {5 http:Response res = new;6 res.statusCode = 500;7 return res;8 }9};1011@test:Config {}12function testGetPet() {13 //mock object that would act as the test double to the clientEndpoint14 clientEndpoint = <http:Client>mock(http:Client, new MockHttpClient());15 http:Response res = getPet("D123");16 test:assertEquals(res.statusCode, 500);17}
Stubbing member functions and variables of an object
The member functions and variables are stubbed to return a specific value or to do nothing when invoked. Using the test module, a default mock object of the specified type. The default action of any member function/variable is to panic upon invocation/retrieval. Subsequent to mock object creation, the required functions and variables of the default mock object should be stubbed to return a value or to do nothing when called.
Samples
Example
Following example shows different ways of stubbing an object member functions.
12@test:Config {}3function testGetPet2() {4 clientEndpoint = <http:Client>mock(http:Client);56 // stubbing to return the specified value7 test:prepare(clientEndpoint).when(“get”).thenReturn(new http:Response());89 // stubbing to return different values for each function call10 test:prepare(mockHttpClient).when("get")11 .thenReturnSequence(new http:Response(), mockResponse);1213 // stubbing to return a value based on input14 test:prepare(mockHttpClient).when("get").withArguments("/pets?id=D123", test:ANY)15 .thenReturn(mockResponse);1617 // stubbing to do nothing when function is called18 smtpClient=<email:SmtpClient>mock(email:SmtpClient);19 test:prepare(mockSmtpCl).when(“send”).doNothing();2021 // add assertions22}
The following example shows how to return a value when a member variable is accessed
1@test:Config {}2function testMemberVariable() {3 clientEndpoint = <http:Client>test:mock(http:Client);4 test:prepare(clientEndpoint).getMember("url").thenReturn("https://foo.com/");5 test:assertEquals(clientEndpoint.url, "https://foo.com/");6}
Functions
[12]
assertEquals | Asserts whether the given values are equal. |
assertExactEquals | Asserts whether the given values are exactly equal. |
assertFail | Assert failure is triggered based on user discretion. |
assertFalse | Asserts whether the given condition is false. |
assertNotEquals | Asserts whether the given values are not equal. |
assertNotExactEquals | Asserts whether the given values are not exactly equal. |
assertTrue | Asserts whether the given condition is true. |
createBallerinaError | Creates an AssertError with custom message and category. |
mock | Creates and returns a mock object of provided type description. |
mockHandler | Inter-op to handle function mocking. |
prepare | Prepares a provided default mock object for stubbing. |
when | Objects and functions related to function mocking Allows a function to stub. |
Classes
[5]
FunctionStub | Represents an object that allows stubbing function invocations |
MemberFunctionStub | Represents an object that allows stubbing member function invocations. |
MemberVariableStub | Represents an object that allows stubbing member variables retrieved. |
MockFunction | Represents a MockFunction object |
MockObject | Represents a Mock object in which to create stubs for member functions and variables |
Records
[5]
AfterGroupsConfig | |
AfterSuiteConfig | |
BeforeGroupsConfig | |
MockConfig | Configuration of the function to be mocked. |
TestConfig | Configuration set for test functions. |
Constants
[6]
ANY | Represents the placeholder to be given for object or record type arguments |
FUNCTION_CALL_ERROR | Represents the reason for function mocking related errors. |
FUNCTION_NOT_FOUND_ERROR | Represents the reason for the non-existing member function related errors. |
FUNCTION_SIGNATURE_MISMATCH_ERROR | Represents the reason for the function signature related errors. |
INVALID_MEMBER_FIELD_ERROR | Represents the reason for the object member field related errors. |
INVALID_OBJECT_ERROR | Represents the reason for the mock object related errors. |
Annotations
[8]
AfterEach | Identifies afterTest function. |
AfterGroups | Identifies afterGroup function. |
AfterSuite | Identifies afterSuite function. |
BeforeEach | Identifies beforeTest function. |
BeforeGroups | Identifies beforeGroup function. |
BeforeSuite | Identifies beforeSuite function. |
Config | |
Mock | Identifies the MockFunction object |
Errors
[6]
Error | Represents mocking related errors |
FunctionCallError | |
FunctionNotFoundError | |
FunctionSignatureMismatchError | |
InvalidMemberFieldError | |
InvalidObjectError |