How unit testing improve my code

Standard

I have a use case. I have a series of mobile ads campaigns with a certain budget and the balance must be updated at a consistent basis. The following are the requirements of the programme:

  1. The budget is to be subtracted by the number of impressions and engagements costs
  2. The rate of the subtraction from the budget depends on the mobile country code of the impression / engagement. (E.g. Thailand is CPM $0.30 CPC $0.03, Malaysia is CPM $0.40 CPC $0.04)
  3. Campaign balance to be updated every 5 minutes
  4. When the time is 0000hrs, update the Daily Budget (Balance / no of days till Campaign end date).
  5. if the campaign is suspended due to overshooting daily budget but still have remaining balance, activate it again at 0000hrs
  6. if the balance is $0, expire the campaign.

As you can see there are a lot of business use cases. To fulfil the requirements, I have a procedural code that meets all the above requirements, but it looks like this:

……….

if ($currentDate->format(‘U’) > $endDateTime->format(‘U’))
$update[‘$set’][‘Status’] = 6;
elseif (($balance <= 0 || $dailyBudget <= 0) && $currentDate->format(‘U’) < $endDateTime->format(‘U’))
$update[‘$set’][‘Status’] = 2;
elseif ($campaign[‘Status’] == 2 && $campaign[‘Balance’] > 0 && $currentDate->format(‘U’) < $endDateTime->format(‘U’) && $currentDate->format(‘G’) == 0)
$update[‘$set’][‘Status’] = 1;
elseif ($campaign[‘Status’] == 1 && $dailyBudget > 0 && $currentDate->format(‘U’) < $endDateTime->format(‘U’) && $currentDate->format(‘G’) == 0) {
$diff = $endDateTime->diff($startDateTime)->format(‘%a’);
if (floor($diff) > 0) {
$update[‘$set’][‘DailyBudget’] = $campaign[‘Balance’] / floor($diff);
$update[‘$set’][‘Balance’] = $balance;
}
}else {
$update[‘$set’][‘Balance’] = $balance;

……………..

Pretty hard to read the code right? The very fact that I did not use CONSTANT and use numbers 1-6 to set the campaign status makes it very difficult code to read! And besides, procedural code is pretty difficult to test, if not not possible to test.

Hence I decide to create a class called CampaignUpdater. The structure of the class will look like this:

<?php class CampaignUpdater{

public function __construct() {    }

public function run(){… with all the if else statement here …}

}

$campaignUpdate = new CampaignUpdater();

$campaignUpdate->run(); ?>

This way I can use the same class to run cron or daemon YET at the same time do unit tests.

But wait, how do I test those business requirements? In order to do that, I break it into another function within run

<?php class CampaignUpdater{

public function __construct() {    }

public function run(){  …..

$this->updateCampaign($campaignId, $DateTime)

….. }

public function updateCampaign($campaignId, $DateTime){

<codes that does all the update>

}

}

$campaignUpdate = new CampaignUpdater();

$campaignUpdate->run(); ?>

From there we will be able to do some simple test function for the 6 business requirements:

function setup(){

$campaign->insert(array(CampaignId=>”1234″, Status=>CAMPAIGN_START_STATUS, Budget=>0, Balance=>0))

}

function testCampaignCancelledWhenBalanceOrBudgetIsZero(){

$DateTime = new DateTime(“NOW”);

$campaignUpdater->updateCampaign(“1234″, $DateTime);

$campaignDetails = $campaign->find(array(CampaignId=>”1234″))

$this->assertEquals($campaignDetails[‘Status’], CAMPAIGN_CANCELLED_STATUS);

}

function tearDown(){

$campaign->remove(array(CampaignId=>”1234”));

}

In conclusion, what I learned about Unit Testing is that it does not just help me just to ensure that my cron job function, it makes my code better by making it more modular and testable. Testing should be as close to the use case as possible. And also try to make your code OO, even if it is to run by cron or daemon.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s