Skip to content

Latest commit

 

History

History
193 lines (144 loc) · 7.92 KB

README.md

File metadata and controls

193 lines (144 loc) · 7.92 KB

PMC Unit Data Mocking

Introduction

We would like to standardize our mocking syntax. When a plugin is upgraded, the data mocker also be easily upgrade and align with the updated plugin code. The data mocking should be developed in conjunction with the plugin to allow code re-use; Documenting how the plugin data is mocked for unit test. Developers should not be required to understand how the plugin work in order to mock the data for testing on another project.

By using a standardized mocking syntax, we will be able to improve the unit test mocking in the future by change the underlying code without touching the existing syntax. Any plugins / custom post update will require the underlying mocker class be updated to align with the plugins. Developers working on plugins are responsible for mocker being backwards compatible as to not break existing mocked method/syntax.

Syntax

  • Mock the default data for a given service/plugin:

      $this->mock->[service]();
    
  • Mock the data with custom data fields:

      $this->mock->[service]( $args );
    
  • Call the specific mock service custom method

      $this->mock->[service]()->custom_method(...);
    
  • Chained statements

      $this->mock->[service]( $args )
          ->custom_method();
    
  • Multiple chained statements may be expose by individual Mocker class custom methods:

      $this->mock->[service]( $args )
          ->custom_method_chained1()
          ->custom_method_chained2()
          ..
          ->custom_method_chainedn();
    

Adding new data mocking class

  • Mocking data that use WP Custom Post type

    • Add a file to tests/mocks folder under the plugin you want the mocker to reside, eg. my-plugin/tests/mocks/mocker.php
    • Use namespace syntax: PMC\My_Plugin\Tests\Mocks;
    • Declare the class complying with PMC naming convention
    • Extending the mocker class from PMC\Unit_Test\Mocks\Post
      1. Must override existing methods; signature must align with inherit parent/abstract classes
        • override method provide_service, this method return the name of the mock service. For example, if we return myplugin; this will cause the mocker class to auto register with pmc unit test frame with to work with syntax: $this->mock->myplugin(...)
        • override method mock, we need to override the post type and force it to our custom post type for my-plugin. Adjust any default post fields as needed.
        • override method seed, we need to override the post type for the default seed to generate multiple random records.
      2. Additional custom mocking methods
        • added optional method reset to clean out mocked data
          • This method will be auto called by the unit test mocker factory during tear down event.
      3. Add other custom method as needed; Any public methods added to the Mocker class will be expose and callable within the PMC UNit Test framework with syntax $this->mock->myplugin()->method_name().
    • Add unit test to verify the mocker class

    Example: my-plugins/tests/mocks/mocker.php

      <?php
      namespace PMC\My_Plugin\Tests\Mocks;
    
      use PMC\Unit_Test\Mocks\Post as Mocker_Base;
    
      final class My_Mocker extends Mocker_Base {
    
          // @codeCoverageIgnore
          public function provide_service() {
              return 'myplugin';
          }
    
          /**
           * @param array $args  Describe the input parameters used for mocking
           * @return My_Mocker
           **/
          publict function mock( array $args = [] ) : self {
    
              // If no parameter passed and data already mocked, we should just return
              if ( 0 === func_num_args() && ! empty( $this->_mocked_post_id ) ) {
                  return $this;
              }
    
              // Setup any custom default parameter here
              $args = array_merge(
                  [
                      'post_title' => 'My Plugin Data Title %d',
                  ],
                  $args
              );
    
              // We need to override the post type to use our custom post type
              $args['post_type'] = 'my-plugin-custom-post-type';
              parent::mock( $args );
    
              // Maybe apply additional processing against mocked post: $this->_mocked_post_id
    
              return $this;
          }
    
          /**
           * Generate multiple mocked post with the provided $args values for each post
           * @param int $count  The number of data records to generate
           * @param array $args Describe the input parameters, @see function mock
           * @return My_Mocker
           */
          public function seed( int $count = 50, Array $args = [] ) : self {
    
              // We need to override the post type to use our custom post type
              $args['post_type'] = 'my-plugin-custom-post-type';
              parent::seed( $count, $args );
    
              // Maybe apply additional processing against seeded posts: $this->_seeded_posts
    
              return $this;
          }
    
      }
    
  • Mocking data that does not involve WP post type.

    • see example class: PMC\Global_Functions\Tests\Mocks\Mock_Device, file ../../pmc-global-functions/tests/mocks/mock-device.php
    • Add a file to tests/mocks folder under the plugin you want the mocker to reside, eg. my-plugin/tests/mocks/mock-my-mocker.php
    • Use namespace syntax: PMC\My_Plugin\Tests\Mocks;
    • Declare the class complying with PMC naming convention
    • Add the class and use the mocker traits: PMC\Unit_Test\Traits\Mocker
    • Implement the mocker interface: PMC\Unit_Test\Interfaces\Mocker
    • Add unit test to verify the mocker class

    Example: my-plugins/tests/mocks/mock-custom.php

      <?php
      namespace PMC\My_Plugin\Tests\Mocks;
      use PMC\Unit_Test\Interfaces\Mocker as Mocker_Interface;
      use PMC\Unit_Test\Traits\Mocker as Mocker_Trait;
    
      final class My_Mocker
          implements Mocker_Interface {
          use Mocker_Trait;
    
          public function provide_service() {
              return 'custom'; // This name must be unique that provide mock syntax: $this->mock->custom(...)
          }
    
          /**
           * Must implement this function
           * @param Array $args Describe the input parameters
           *    The input parameters should be Array type;
           *    For specialized custom mock that don't use array, other data type can be use
           * @return My_Mocker
           **/
          public function mock( Array $args = [] ) : self {
    
              if ( 0 === func_num_args() ) {
                  // Do something if no arguments pass to indicate calling syntax: $this->mock->custom()
                  return $this;  // Must return current object $this
              }
    
              // do something to mock the data
    
              return $this;  // Must return current object $this
          }
    
          /**
           * Optional function to clean out the current mocked data
           **/
          public function reset() {
              // clean up any mocked data
          }
    
          /**
           * Addition custom mock method
           * Provide unit test mocking syntax: $this->mock->custom()->custom_method();
           **/
           public function custom_chained_method() {
              // some custom code
              // Function may or may not return a value
           }
    
          /**
           * Addition custom mock method that support chained statements
           * Provide unit test mocking syntax: $this->mock->custom()->custom_chained_method();
           * @return My_Mocker
           **/
           public function custom_chained_method() : self {
              // some custom code
              return $this; // Required this to support chained statements
           }
    
    
    
      }