0

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!

  • As a general rule, static methods and unit testing don't mix. – GordonM Jun 01 '14 at 19:55
  • You read the PHPUnit documentation and followed the examples in there? – hek2mgl Jun 01 '14 at 20:01
  • @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 ...? –  Jun 01 '14 at 20:14
  • @hek2mgl Yes I saw the documentation; I just mostly saw different assert methods; but I really dont know how I can test my code, in which I have used PDO and DB queries? Thanks –  Jun 01 '14 at 20:15
  • You read also the section named "Database Testing" ? – hek2mgl Jun 01 '14 at 20:18
  • @GordonM What you are saying is not fully true, especially in this case. static methods can be problematic for tests, you are right, but only if they set some state. This is not the case here. Therefore the method can be tested without problems. – hek2mgl Jun 01 '14 at 20:24
  • @hek2mgl I almost reviewed the documentation you said now! But still it is vague for me to test my function! Can you please help me with one test case for my code? It will definitely help me...Thanks in advance –  Jun 01 '14 at 22:38
  • 1
    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 Jun 01 '14 at 22:47
  • Yes you are right! I needed to read that section first! But now even after going through the examples in documentation I guess they are kind of different to my methods, or maybe I could not correlated them to my method correctly! Anyway by any chance if you had a time and could figure it out, I really appreciate your help... –  Jun 01 '14 at 22:51
  • 1
    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 Jun 01 '14 at 22:53
  • Sure; in the meantime I will do more research and find more examples; I really appreciate your help :-) –  Jun 01 '14 at 22:56
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/54940/discussion-between-hek2mgl-and-user3421904). – hek2mgl Jun 02 '14 at 18:12
  • Sorry I missed your chat; I left you some messages in the chat room; Im not sure if you still can see them or not; I just want to know if by any chance I can chat with you over the weekend? I REALY appreciate your help; any time on the weekend! –  Jun 03 '14 at 02:24

2 Answers2

0

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.

pgampe
  • 4,531
  • 1
  • 20
  • 31
  • Thanks for the response! Yes I guess you are right! I need to do some "functional testing" But could you please let me know what is the best way to do it? Any small example to clarify more please? –  Jun 01 '14 at 22:29
  • Did I understand correctly that there is no need to use the command from PHPUnit like getDataSet(), datasets,datatables, assert.... Do I need to call the functions individually and use var_dump or print_r to see the returned values with the expected results? Could you please write one functional testing for my code to make it clearer please? –  Jun 01 '14 at 22:34
  • Please take a look at http://phpunit.de/getting-started.html. Once you have concrete questions, please come again and I will help you sort out the details. – pgampe Jun 02 '14 at 08:32
  • +1. But Isn't this integration testing? Functional testing tests the functionality of a program that a product owner can understand. Integration testing check either the innards of one system, or combining multiple systems together to do something useful. – Tomás Jun 03 '14 at 13:08
  • Depends of your definition of multiple systems. E.g. in the PHP world, the database is considered part of the application logic, because both are really closely coupled. Therefore you cannot do functional testing without a database. You could try to mock it away, but I doubt that you will actually get useful tests for this and it would be very memory heavy. Integration testing is (at least for me) if you test over multiple loosely coupled services. E.g. test a CMS in combination with an image server, test user replication between two systems, etc. But that is really up how you define it. – pgampe Jun 03 '14 at 16:06
  • Thanks for your explanation! Sorry if I'm getting back to you late! I have written my test case and came up with two questions; I really appreciate your help: I have posted my questions in the following link since my question is kind of different: http://stackoverflow.com/questions/24175487/functionality-testing-and-test-database-data-for-phpunit –  Jun 12 '14 at 02:49
0

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!

Tomás
  • 3,501
  • 3
  • 21
  • 38
  • Thanks so much for your reply :-) 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? –  Jun 04 '14 at 02:41
  • If you want to do unit testing on the layers that are above, you must stub the method `get_accepted_images` to return whatever you want. With a static method, you hide the dependencies from objects, thus is impossible to inject the mocked object and to use a stubbed method. – Tomás Jun 04 '14 at 07:19
  • Hi, thank you for your nice explanation!sorry if I'm getting back to you late! Your explanation was so nice, but I guess you are assuming that I want to test other function, in which I used this static function, but I would like to make it simple and assume that I just have static functions in which I dont call any other static methods(please even ignore WS_Utility::paginate_array() ); –  Jun 12 '14 at 02:46
  • for some reason I cannot change the static methods, although it is worth mentioning that in those static methods I dont call any other static methods and I just need to test these static methods and based on this link(http://stackoverflow.com/questions/5961023/unit-testing-and-static-methods) and explanations here, if I dont have any static methods in side that function, the testing would be fine! so I have come up with two more questions which I really appreciate your help! –  Jun 12 '14 at 02:46
  • since the question is different I have crated a new post (http://stackoverflow.com/questions/24175487/functionality-testing-and-test-database-data-for-phpunit) and I thank you in advance! :-) –  Jun 12 '14 at 02:47
  • 1
    I agree. If you are not going to test another function that will use this static method, then is correct to leave it static if you want more simplicity. :) – Tomás Jun 15 '14 at 08:09