public function addPic($loggedInId,$PicId){
$chatCoverPhotoObj = new COVER_PHOTO();
$out = $chatCoverPhotoObj->add($loggedInId,$PicId);
if($out)
return true;
return false;
}
Above sample code is written in php and simple add record in table COVER_PHOTO
Record : "picId" corresponding to loggedin user identified by "loggedInId".
I want know what should i write in unit test of this function.
Or for such function we should not write unit test.
Please suggest?
Firsty, if your System-/Class Under Test is using anything that is infrastructural concern -which in your case is the database- that tends to be an integration test.
Unit test are happening in complete isolation with every possible dependencies mocked/stubbed out.
The first problem I see in your code is that you new() up a dependency of your function. By this you can't really easily test your code.
I suggest that you better invert this dependency and have an interface in the constructor of your class, which can receive the concrete implementation of that interface. Once this is done, you can mock out the database part in your test. However by looking at the code you have shared in your question I'm not really convinced what behaviour you are going to test here.
Always make sure what you want to test for, in this case like persistence specification or the mapping configuration (of course in case you are using some sort of an OR/M). Just checking the return value -which is the success or failure flag- of the persistence operation doesn't add much business value to test against.
Related
I’m just diving into testing/test driven development in php, and am a bit confused about how to handle a very typical scenario in our legacy codebase. Our codebase does not have many classes, it’s very functional programming oriented.
In this example code, which is pseudocode, I want to write a test for getAndOrderUsersByAge(). As you can see it first gets all the users from our database (in a giant array lets say, because we don’t have objects/classes) then sorts them. This is of course a VERY common occurrence in our code, manipulating or analyzing data gotten from the database; not objects, but an array of database rows basically.
Note that I've added an error in the if statement to simulate an error I want my tests to catch.
//gets all users in our db into an array, then sorts them by age
function getAndOrderUsersByAge(){
//get all users from the db
$all_users = getAllUsers();
//sort
$all_users_sorted = sortUsers($all_users)
//notice I've made a mistake here on purpose, left the "d" off of "$all_users_sorted"
//so the function will always return false, a mistake...which I want tests to catch
if(!empty($all_users_sorte){
return $all_users_sorted;
}
else{
return false;
}
}
My questions are:
1.) Is testing the function getAndOrderUsersByAge() unit testing, integration testing, or …?
2.) In my (unit?) test(s) of getAndOrderUsersByAge(), I want to assume that getAllUsers (the function which gets things from the db) behaves correctly because I only want to test getAndOrderUsersByAge() right? I’m not really sure what “concept” this falls under when I’m reading the two books I have on testing. Is this where I would “mock”, e.g. create some fake data for getAllUsers() to return?
3.) What tests would you write for getAndOrderUsersByAge()? I think I would write one that ensures a non-empty array is returned when getAllUsers() returns a non-empty array, as this would catch the error I've created. I'm not sure what else though.
Any tips, recommended reading material, etc. is very welcomed.
1.) Is testing the function getAndOrderUsersByAge() unit testing, integration testing, or …?
Any test that you do at code level is unit testing, basically testing methods , classes, interfaces. Tests that validate a unit or block of code.
2.) In my (unit?) test(s) of getAndOrderUsersByAge(), I want to assume that getAllUsers (the function which gets things from the db)
You can test getAndOrderUsersByAge() by actual data or mock data. Mock data is preferred so you will have more control on the test and you can create more test cases for sortUsers function.
3.) What tests would you write for getAndOrderUsersByAge()?
The test should be of nature that would validate your sortUsers function. I am not sure how your data looks but some tests could be:
1) data set that will have valid data , which will pass the test
2) data set that has invalid data like special characters in name
3) data set that has junk in age field or floating numbers or out of range integers, basically test how your function behaves when age has different type of data
4) data set that has null values
5) data set with 1 element array
6) data set with repeated element array
7) data set with invalid types in array
I'm using the MVC pattern in a CodeIgniter PHP project and I'm wondering what's the best way to build methods of the models in order to ensure readability of the code and scalability.
In short, is this better to do this ? :
public function set_account_state($new_state) {
// UPDATE a database record state to $new_state [0, 1 or 2]
}
Or this ? :
public function reject_account() {
// UPDATE a database record state to 0
}
public function accept_account() {
// UPDATE a database record state to 1
}
public function pending_account() {
// UPDATE a database record state to 2
}
Or maybe another way ?
Also, is there a good practice for function naming in such cases ?
function set_account_state($state)
This is better when you have only one task and that is to change the state.
But if in future you might have to do different tasks before you change the account state then you need three different methods.
You can still have that original method to change the state of the account and call it from your three methods.
Function naming should include a verb with nouns to make it clearer.
function pending_account() is not that clear, function keep_account_pending() is I feel a better way to name it.
In my opinion, the second way is the better way.
Using names that indicate what will the method do can improve the readability of the code.
As your code grows bigger, it's easy to forget what number represents what state. That does not happen with names because a method called reject_account() will indicate that account will be rejected better then a number passed as argument to a function.
Also when other people work on your code, it will be easier for them to understand what is going on when a method is called. Having said that, it's better for one understand that the client account is accepted when one sees a method called accept_account() then when one sees set_account_state(1).
quick example of dataProvider:
return [
['180d-1pc', '6m-1pc'],
]
and test:
public function test_convert($title, $expected)
{
$uut = new Converter();
$this->assertEquals($expected, $uut->convertDayTitle($title));
}
(simply put: test if we convert 180d(days) to 6m(months))
as you can see - in data provider there are input data defined and also an expected output.
This works fine in many cases, but I keep having this feeling that maybe it's not the best idea. So I'm wondering if could be considered bad practice. If so - when I will see it was a bad idea to do it?
One example is, when you would like to use the same dataProvider in two tests - should you define two expected values and use one of them?
Quick example (I just made that up, so don't pay attention that I make product object just from title ;)):
public function test_gets_discount_when_licence_period_longer_than_1year($title, $expectedTitle, $expectedDiscount) {
$prod = new Product($title);
$this->assertEquals($expectedDiscount, $product->hasDiscount();
}
How to make this more elegant?
What you're doing is totally fine. Data providers can, and should, include the expected test result.
About the issue of reusing the same dataProvider for 2 tests, and only using some fields: I'd say that if the fields are related (i.e. they are properties of the same object), it can be acceptable.
If you feel the dataProvider is getting too big and complex because 2 tests must use data from it, just create 2 separate dataProviders, and use another private common method for building the common data.
Assuming I have a controller method that looks something like this:
public function someRoute()
{
if(some condition) {
return View::make('view1');
}
return View::make('view2');
}
How would I assert in my unit test that view1 was returned as opposed to view2? A colleague mentioned that if I can get the HTML response as a string then I can just use PHPUnit's assertRegExp against the returned HTML to match a given string only found in view1, but that doesn't seem right to me.
Is there a better way? A deeper question may be should I even need to worry about which view is returned in my unit test or if I should just $this->assertResponseOk() ?
You are mixing unit test with acceptance tests, so you have two options:
1) Split those tests to unit and acceptance, and use a tool like Codeception to help you do acceptance, which is way more elegant than PHPUnit for this kind of test. With Codecption you would do things like:
$I->amOnPage('/someUrl');
$I->see('John Doe');
2) Do what your friend told you to do.
I have a class let's say Person. The ORM layer has generated based on the sql structure the corresponding objects. The class person has a method: Get($id). In the Get method, the object Person is called and the field from the table are retrieved.
I basically want to make the following unit test: create a new person and check if the Get method is returning the right information.
How is the unit testing supposed to work in this condition ?
Do I need to create a separate database ( just the structure ), and make the creation/selection from that database?
Should the boostrap file load the same configuration as the framework I'm using but change the configuration file so It works with the fake database ?
Should I clean the new database each after each test ?
I was also wandering after seeing your responses if simulating an ORM response without actually building a new database is not the way to go ?
How is the unit testing supposed to work in this condition ?
Generally, you should split your unittests mentally in two parts:
one part of your code is testable without the database, so you can stub or mock the methods that do the database access
the other part of your tests needs to work with the database, since it tests if the ORM is used correctly.
Do I need to create a separate database
This depends on your needs. Rails apps generally have testing/development/production "environments" - database, configuration, storage directories.
Testing is for running unit tests, dev for developing things and production for running the live server. While developing, you run against the dev configuration and thus your development database. For unit tests, the testing env is used which has the benefit that i.e. users in the database are not deleted or broken.
I like that concept; in my phpunit tests I often do have a switch in the bootstrap that changes which configuration file is loaded. Just remember that your development database often contains more data than a single unit test needs, and you probably hand-crafted that data and do not want to lose. Also, another database does not cost money.
Should I clean the new database each after each test?
I mostly clean the tables only that will be used in the test. Cleaning your database makes sure you don't get side-effects from previous tests.
Check out Phactory. I prefer it over the database extensions included in PHPUnit and it makes it really easy to insert records into your test db.
require_once 'Phactory/lib/Phactory.php';
Phactory::setConnection(new PDO('sqlite:test.db'));
Phactory::define('user', array('name' => 'Test User',
'email' => 'user#example.com'));
$user = Phactory::create('user'); // creates a row in the 'users' table
print("Hello, {$user->name}!"); // prints "Hello, Test User!"
Your System Under Test (SUT) will need to connect to your test database. The idea is that you populate just the records you need for the method you are testing. The orm layer shouldn't matter if the test db has all the same tables and fields as your production database.
PHPUnit also provides some help with this, have a look at Database Testing.
Essentially you can write you Test classes so that they extend PHPUnit_Extensions_Database_TestCase and then use the getConnection() and getDataSet() functions to load up data for the test.
require_once 'PHPUnit/Extensions/Database/TestCase.php';
class PersonTest extends PHPUnit_Extensions_Database_TestCase
{
protected function getConnection() {
$pdo = new PDO('mysql:host=localhost;dbname=application_test', 'root', '');
return $this->createDefaultDBConnection($pdo, 'application_test');
}
protected function getDataSet() {
return $this->createMySQLXMLDataSet('person.xml');
}
Then you can define exactly what you want to test in the database in the XML.
You can also assert that the resulting DataSet from your tests is equal to what you expect with:
public function testCreate() {
// Execute some code with your ORM to create a person.
$actual = new PHPUnit_Extensions_Database_DataSet_QueryDataSet($this->getConnection());
$actual->addTable('person');
$expected = $this->createMySQLXMLDataSet('person_create_expected.xml');
$this->assertDataSetsEqual($expected, $actual);
}
In this example, we are only comparing the resulting person table... So person_create_expected.xml should only contain the person table as well.
To create the XML's you can use mysqldump.
mysqldump --xml -t -u root -p application_test > person.xml