I don't have much experience with testing but I'm trying to make it part of my routine to develop better software.
The class below is a service class in Laravel. It needs to save a record on the database, saving the customer's customer_id
, a route (location_id_from
and location_id_to
) and which location to bill (location_id_bill
). The billing location can be null, in which case it will try to determine which one to use.
The code works, but I don't see how to completely unit test the newJob
function. From what I've learned so far, I could replace the static methods whereId
with an injected repository in the constructor.
Regarding the validation, I'm currently doing the validation, and if it doesn't passes, it will throw an exception with all errors messages.
So:
- how to test the actual job creation without touching the database
- is there a better way to do the validation?
class Job
{
public function newJob(int $customer_id, int $location_id_from, int $location_id_to, int $location_id_bill): \App\Models\Customer\Job
{
$location_from = Location::whereId($location_id_from);
$location_to = Location::whereId($location_id_to);
if ($location_id_bill === null) {
$location_bill = Location::whereId($location_id_bill);
} else {
$location_bill = new Location();
}
$errors = $this->newJobValidate($customer_id, $location_from, $location_to, $location_bill);
if (count($errors)) {
throw ValidationException::withMessages($errors);
}
$job = new \App\Models\Customer\Job();
$job->customer_id = $customer_id;
$job->location_id_from = $location_from->id;
$job->location_id_to = $location_to->id;
$job->location_id_bill = $location_bill->id;
$job->save();
return $job;
}
private function newJobValidate(int $customer_id, Location $location_from, Location $location_to, Location $location_bill)
{
$errors = [];
if ($location_to->type === Location::TYPE_COMMON && $location_from->type === Location::TYPE_COMMON) {
// same location, but not customer's
$errors[] = __('job.errors.same_location_common');
}
if ($location_to->type === Location::TYPE_CUSTOMER && $location_to->customer->customer_id !== $customer_id ||
$location_from->type === Location::TYPE_CUSTOMER && $location_from->customer->customer_id !== $customer_id) {
$errors[] = __('job.errors.location_doesnt_belong_to_customer');
}
if ($location_bill->id === null) {
if ($location_to->type === Location::TYPE_CUSTOMER && $location_from->type === Location::TYPE_CUSTOMER) {
$errors[] = __('job.errors.must_select_bill_location');
} elseif ($location_from->type === Location::TYPE_CUSTOMER) {
$location_bill->id = $location_from->id;
} else {
$location_bill->id = $location_to->id;
}
}
if ($location_bill->id !== $location_from->id && $location_bill->id !== $location_to->id) {
$errors[] = __('job.errors.bill_location_different');
}
return $errors;
}
}
```