Test Case Conventions



Test Case Conventions

0 0


lecture


On Github vinchi777 / lecture

Test Case Conventions

Like most things in CakePHP, test cases have some conventions. Concerning tests:
  • PHP files containing tests should be in your app/Test/Case/[Type] directories.
  • The filenames of these files should end in Test.php instead of just .php.
  • The classes containing tests should extend CakeTestCase, ControllerTestCase or PHPUnit_Framework_TestCase.
  • Like other class names, the test case class names should match the filename. RouterTest.php should contain class RouterTest extends CakeTestCase.
  • The name of any method containing a test (i.e. containing an assertion) should begin with test, as in testPublished(). You can also use the @test annotation to mark methods as test methods.
Creating Your First Test Case
 

										class ProgressHelper extends AppHelper {
												public function bar($value) {
														$width = round($value / 100, 2) * 100;
														return sprintf(
																		'<div class="progress-container">
																		<div class="progress-bar" style="width: %s%%"></div>
																		</div>', $width);
												}
										}
										
 
										App::uses('Controller', 'Controller');
										App::uses('View', 'View');
										App::uses('ProgressHelper', 'View/Helper');

										class ProgressHelperTest extends CakeTestCase {
												public function setUp() {

												}

												public function testBar() {

												}
										}
										
 
										public function setUp() {
												parent::setUp();
												$Controller = new Controller();
												$View = new View($Controller);
												$this->Progress = new ProgressHelper($View);
										}
										

Running Tests

Running Test in a browser

http://localhost/your_app/test.php.

Running Test in command line
					# Run a model tests in the app
					./Console/cake test app Model/Article

					# Run a component test in a plugin
					./Console/cake test DebugKit Controller/Component/ToolbarComponent

					# Run the configure class test in CakePHP
					./Console/cake test core Core/Configure
					

Test Case Lifecycle Callbacks

Test cases have a number of lifecycle callbacks you can use when doing testing:

setUp is called before every test method. Should be used to create the objects that are going to be tested, and initialize any data for the test. Always remember to call parent::setUp() tearDown is called after every test method. Should be used to cleanup after the test is complete. Always remember to call parent::tearDown(). setupBeforeClass is called once before test methods in a case are started. This method must be static. tearDownAfterClass is called once after test methods in a case are started. This method must be static.

Fixtures

Creating fixtures

class ArticleFixture extends CakeTestFixture {

      // Optional.
      // Set this property to load fixtures to a different test datasource
      public $useDbConfig = 'test';
      public $fields = array(
          'id' => array('type' => 'integer', 'key' => 'primary'),
          'title' => array(
            'type' => 'string',
            'length' => 255,
            'null' => false
          ),
          'body' => 'text',
          'published' => array(
            'type' => 'integer',
            'default' => '0',
            'null' => false
          ),
          'created' => 'datetime',
          'updated' => 'datetime'
      );
      public $records = array(
          array(
            'id' => 1,
            'title' => 'First Article',
            'body' => 'First Article Body',
            'published' => '1',
            'created' => '2007-03-18 10:39:23',
            'updated' => '2007-03-18 10:41:31'
          ),
          array(
            'id' => 2,
            'title' => 'Second Article',
            'body' => 'Second Article Body',
            'published' => '1',
            'created' => '2007-03-18 10:41:23',
            'updated' => '2007-03-18 10:43:31'
          ),
          array(
            'id' => 3,
            'title' => 'Third Article',
            'body' => 'Third Article Body',
            'published' => '1',
            'created' => '2007-03-18 10:43:23',
            'updated' => '2007-03-18 10:45:31'
          )
      );
 }

Testing Models

App::uses('Article', 'Model');

class ArticleTest extends CakeTestCase {
    public $fixtures = array('app.article');

    public function setUp() {
        parent::setUp();
        $this->Article = ClassRegistry::init('Article');
    }

    public function testPublished() {
        $result = $this->Article->published(array('id', 'title'));
        $expected = array(
            array('Article' => array('id' => 1, 'title' => 'First Article')),
            array('Article' => array('id' => 2, 'title' => 'Second Article')),
            array('Article' => array('id' => 3, 'title' => 'Third Article'))
        );

        $this->assertEquals($expected, $result);
    }
}

Mocking Models

public function testSendingEmails() {
    $model = $this->getMockForModel('EmailVerification', array('send'));
    $model->expects($this->once())
        ->method('send')
        ->will($this->returnValue(true));

    $model->verifyEmail('test@example.com');
}
	

Testing Controllers

 class ArticlesControllerTest extends ControllerTestCase {
    public $fixtures = array('app.article');

    public function testIndex() {
        $result = $this->testAction('/articles/index');
        debug($result);
    }

    public function testIndexShort() {
        $result = $this->testAction('/articles/index/short');
        debug($result);
    }

    public function testIndexShortGetRenderedHtml() {
        $result = $this->testAction(
           '/articles/index/short',
            array('return' => 'contents')
        );
        debug($result);
    }

    public function testIndexShortGetViewVars() {
        $result = $this->testAction(
            '/articles/index/short',
            array('return' => 'vars')
        );
        debug($result);
    }

    public function testIndexPostData() {
        $data = array(
            'Article' => array(
                'user_id' => 1,
                'published' => 1,
                'slug' => 'new-article',
                'title' => 'New Article',
                'body' => 'New Body'
            )
        );
        $result = $this->testAction(
            '/articles/index',
            array('data' => $data, 'method' => 'post')
        );
        debug($result);
    }
}

You can choose from a number of ways to inspect the success of your controller action. Each offers a different way to ensure your code is doing what you expect:

vars Get the set view variables. views Get the rendered view, without a layout. contents Get the rendered view including the layout. result Get the return value of the controller action. Useful for testing requestAction methods.

Using mocks in test action

public function testAdd() {
    $Posts = $this->generate('Posts', array(
        'components' => array(
            'Session',
            'Email' => array('send')
        )
    ));
    $Posts->Session
        ->expects($this->once())
        ->method('setFlash');
    $Posts->Email
        ->expects($this->once())
        ->method('send')
        ->will($this->returnValue(true));

    $this->testAction('/posts/add', array(
        'data' => array(
            'Post' => array('title' => 'New Post')
        )
    ));
    $this->assertContains('/posts', $this->headers['Location']);
}

public function testAddGet() {
    $this->testAction('/posts/add', array(
        'method' => 'GET',
        'return' => 'contents'
    ));
    $this->assertRegExp('/contents);
    $this->assertRegExp('/
view); }