0
votes

I'm very new to Unit testing; I need to use PHPUnit test to write test cases! Since I have not seen any test cases, I do not know exactly how I can test, how I can write test cases... If you can help me to test one of my small methods, I can get a good vision of testing and understand the logic. So I was wondering if you would mind helping me with testing the following method (perferably with PHPUnit, but any other testcases can help me to understand the logic as well):

static public function get_accepted_images($limit, $page, $uuid) {

    try {
        $conn = new pdo_connect();

        $query = "  SELECT ....";

        $result = $conn->prepare($query);
        $result->bindParam(':uuid', $uuid);
        $result->execute();
        $array_result = $result->fetchAll(PDO::FETCH_OBJ);
        $paginate_result = WS_Utility::paginate_array($array_result, $page, $limit);
        $result_Set = array($paginate_result, TRUE);
    } catch (Exception $e) {

        $result_Set = array($e->getMessage(), FALSE);
    }


    return $result_Set;
}

If you need more clarification, please let me know and your help is totally appreciated!

2
As a general rule, static methods and unit testing don't mix.GordonM
You read the PHPUnit documentation and followed the examples in there?hek2mgl
@GordonM Thanks for your reply! So what should I do in this case? Do I need to convert them one by one to non-static methods just for testing ...?user3421904
I have to admit, that I need to re-read the docs for myself again before I can give you a good answer. The database test interface of PHPUnit has changed significantly since I've used it the last time. However, I can do that and will give you an example then. For me it was important that you read and understand that documentation because this is the minimal basis for understanding answers here. Also it is likely that you will need to refactor your code in order to gain testability.hek2mgl
Ok. Await my answer tomorrow, here it is late today. You should follow the tutorials from the docs, independently of your code during this. This will help to get familiar with it.hek2mgl

2 Answers

0
votes

First you should change this method to non-static.

public function get_accepted_images($limit, $page, $uuid) {
    try {
        $conn = new pdo_connect();
        $query = "SELECT...";
        $result = $conn->prepare($query);
        $result->bindParam(':uuid', $uuid);
        $result->execute();
        $array_result = $result->fetchAll(PDO::FETCH_OBJ);
        $paginate_result = WS_Utility::paginate_array($array_result, $page, $limit);
        $result_Set = array($paginate_result, TRUE);
    } catch (Exception $e) {
        $result_Set = array($e->getMessage(), FALSE);
    }
    return $res;
}

Next thing is work on this method with some integration testing (NOT UNIT TESTING).
When you do integration testing you don't care how the method is implemented, but you should know precisely the contract of the method (for ex: on this input ill receive this output, on this context ill receive this exception, etc etc)

Based on this knowledge of this method contract you start doing the integration tests:

class ImageDatabaseHelperIntegrationTest extends PHPUnit_Framework_TestCase
{
//The most simple test. When no images exists in the DB what happens?
public function testWhenNoImagesExistsReturnCorrectResult() {
    $sut = new ImageDatabaseHelper(); //I dont know what is the name of the class
    $actual = $sut->get_accepted_images(1,1,1);
    $expected = array(null, FALSE); //?? I dont know what the result is. you know this
    $this->assertEquals($expected, $actual);
}


//You should keep doing like this. 
//The next tests will include inserting data in the database, and testing what is the output




EDIT:

user3421904 wrote: But why not static? Cant we do it like: $actual = images::get_accepted_images(1, 1, 11); this one works on my end as well! Is it wrong?

Is not wrong. But if you are going to unit test other component that consumes ImageDatabaseHelper you will not be able to mock it. Here is why:

Let's say that you are using an ImageService class which consumes directly the get_accepted_images static method. Like this:

class ImageService {

    public function getAcceptedImages() {
        $images = ImageDatabaseHelper::get_accepted_images(1,1,1);

        //...
        //more code 
        //...

        return $images;
    }
}

How do you test the getAcceptedImages method without accessing the DB? You can't, right?

Now imagine that you do the method non-static.

class ImageService {
    private $imageDatabaseHelper;

    public function __construct(ImageDatabaseHelper $imageDatabaseHelper = null) {
       if(!$imageDatabaseHelper) {
          $this->imageDatabaseHelper = new ImageDatabaseHelper();
       }
       else {
          $this->imageDatabaseHelper = $imageDatabaseHelper;
       }
    }


    public function getAcceptedImages() {
        $images = $this->imageDatabaseHelper->get_accepted_images(1,1,1);

        //...
        //more code 
        //...

        return $images;
    }
}

This can be tested easily!!!

class ImageServiceTest extends PHPUnit_Framework_TestCase {
    protected $sut;    

    protected $imageDatabaseHelperDouble;

    public function setUp() {
      $this->imageDatabaseHelperDouble = $this->getMockBuilder('ImageDatabaseHelper')->disableOriginalConstructor()->getMock();
      $this->sut = new ImageService($this->imageDatabaseHelperDouble);
    }


    public function testGetAcceptedImagesWhenCalledShouldCallImageDatabaseHelper() {
       $this->imageDatabaseHelperDouble->expected($this->once())->method('get_accepted_images')->with(1,1,1);
       $this->sut->getAcceptedImages();
    }


    public function testGetAcceptedImagesWhenCalledShouldReturnImages() {
       $this->imageDatabaseHelperDouble->expected($this->any())->method('get_accepted_images')->will($this->returnValue(array("hi im an image", "me tooo")));
       $actual = $this->sut->getAcceptedImages();

       $expected = array("hi im an image", "me tooo");
       $this->assertEquals($expected, $actual);
    }

}

You see? The mocked ImageDatabaseHelper overrides the original ImageDatabaseHelper used by ImageService and he thinks he is using it. From this you can do whatever you want! (this also includes making ImageDatabaseHelper throw exceptions!)

Have fun!

0
votes

You cannot unit test this method, because it has too many side effects. Especially the result will differ depending on the database selected.

To test this method, you will need to do functional testing. This is not much different from unit testing (and can be done by phpunit too, but you need to prepare the database before running the test. That way, you will get a predictable result and you can test the logic of your function.

I do not see much sense in testing the above method, but I suggest to rather test WS_Utility::paginate_array(), because this one is the only function call that does any logic, besides fetching from DB of course.