# Get Started - [Introduction](#intorduction) - [Recommendation](#recommendations-for-writing-effective-test-cases) - [Organize Test Cases](#organize-test-cases) - [Unit Test and Integration Test](#when-to-use-unit-test-and-integration-test) - [Write Test Case](#write-test-case) - [API Test](#api-test) - [AJAX Test](#ajax-test) - [Unit Test](#unit-test) - [Grouping Test Cases](#grouping-test-cases-in-phpunit) - [Custom Assertion](#available-custom-assertion) - [Database Assertion](#database-assertion) - [Nested Array Assertion](#nested-array-assertion) - [Mocking](./mocking.md) ## Introduction Our test case class should extend the [DokanTestCase](./../../tests/php/src/DokanTestCase.php#L14) class. ### Recommendations for Writing Effective Test Cases 1. **Isolate the SUT**: Ensure that your tests are isolated and only test the SUT (*System under test*) without external dependencies. 2. **Use Meaningful Test Names**: Use descriptive names for your test methods to indicate what they are testing. 3. **Test Edge Cases**: Include test cases for edge conditions and potential error scenarios. 4. **Maintain Readability**: Write clean and readable test code. Use comments if necessary to explain complex logic. 5. **Keep Tests Independent**: Ensure that each test is independent of others and does not rely on any shared state. ### Organize Test Cases A well-organized directory structure is crucial for maintaining clarity and manageability. Here’s an example structure: ``` plugin-dir/ │ ├── tests/ │ ├── php/ │ │ ├── src/ │ │ │ ├── Unit/ │ │ │ │ └── ClassTest.php │ │ │ ├── Integration/ │ │ │ │ └── ClassIntegrationTest.php │ │ │ └── TestCase.php │ │ └── bootstrap.php │ │ │ └── pw/ │ └── Files and folders for the Playwright tests │ └── ... Other files ``` We can follow the same file path of the source. For example, the test case file for `includes/Services/MyService.php` could be `tests/php/src/Unit/MyServiceTest.php` or `tests/php/src/Integration/MyServiceTest.php`. ### When to Use Unit Test and Integration Test #### Unit Tests - Use unit tests for core logic, utility functions, and isolated classes. - Aim to cover as much of your code as possible with unit tests. - Run unit tests frequently during development to catch issues early. #### Integration Tests - Use integration tests for verifying interactions between components. - Test scenarios that involve multiple units working together. - Run integration tests to ensure that different parts of your system work well together, especially after major changes or before releases. #### Best Practices - **Balance**: Maintain a good balance between unit tests and integration tests. Both are crucial for comprehensive test coverage. - **Mocking**: Use mocking frameworks (e.g., Mockery, Brain Monkey) to isolate components during unit testing. - **Environment**: Set up a controlled environment for integration testing to avoid side effects and ensure repeatability. ## Write Test Case To write unit tests in Dokan smoothly, your test class should extend the `WeDevs\Dokan\Test\DokanTestCase` abstract class. For example ```php assertTrue( true ); } } ``` > If `$is_unit_test` is `true` then `DokanTestCase` will not create utility for the API and Database. ### API Test There are two utility methods named `get_request` and `post_request` in the `DokanTestCase` class. ```php server->get_routes( $this->namespace ); $full_route = $this->get_route( 'my-route' ); // Assert route is registered. $this->assertArrayHasKey( $full_route, $routes ); // Assert route is registered only for GET method. $this->assertNestedContains( [ 'methods' => [ 'GET' => true ] ], $routes[ $full_route ] ); } // GET & POST request test. public function test_sample_method() { // GET request. $response = $this->get_request( 'route', $filter_params ); $data = $response->get_data(); $status_code = $response->get_status(); // POST request. $response = $this->post_request( 'route', $request_params ); $data = $response->get_data(); $status_code = $response->get_status(); // PUT request $response = $this->put_request( 'route', $update_params ); $data = $response->get_data(); $status_code = $response->get_status(); // DELETE request $response = $this->delete_request( 'route', $delete_params ); $data = $response->get_data(); $status_code = $response->get_status(); } } ``` `$filter_params` and `$request_params` are the array of `key => value`. ### Ajax Test You should extend the `DokanAjaxTestCase` to write the the ajax test. ```php factory()->seller->create(); // Set the current user to the created seller wp_set_current_user( $user ); // Set up POST variables $_POST['nonce'] = wp_create_nonce( 'dokan_withdraw_make_default' ); $_POST['action'] = 'dokan_withdraw_handle_make_default_method'; $_POST['method'] = 'paypal'; // Handle the AJAX request try { $this->_handleAjax( 'dokan_withdraw_handle_make_default_method' ); } catch ( WPAjaxDieContinueException $e ) { // Catch the die() statement in AJAX handling $this->fail( $e->getMessage() ); } wp_set_current_user( $user ); // Get the last response $response = $this->_last_response; if ( empty( $response ) ) { $this->fail( 'No response from AJAX handler' ); } // Decode the JSON response $data = json_decode( $response, true ); if ( json_last_error() !== JSON_ERROR_NONE ) { $this->fail( 'Invalid JSON response: ' . json_last_error_msg() ); } } } ``` ### Unit Test Unit tests should be independent of external sources such as databases, APIs, etc. They must always return the expected result. Set the `$is_unit_test` property to `true` when writing unit tests by extending the `DokanTestCase` class. ```php In our case, We may group our test cases by `module-name`. #### How to Group Test Cases To group test cases, simply add the `@group your-group-name` annotation above your test method or class. Here's an example: ```php factory()->product->create( [ 'status' =>'publish' ] ); $this->assertDatabaseHas( 'posts', [ 'status' => 'publish' ] ); $this->assertDatabaseCount( 'posts', 1, [ 'ID' => $product_id ] ); ``` #### Nested Array Assertion We may use `assertNestedContains` if It is required to assert value to a nested Array. ```php $array = [ 'key1' => [ 'subkey1' => 'value1', 'subkey2' => 'value2' ], 'key2' => 'value3' ]; // Use the custom assertion method $this->assertNestedContains( [ 'subkey1' => 'value1' ], $array ); $this->assertNestedContains( [ 'key2' => 'value3' ], $array ); ```