How to Make Your Laravel App More Testable

Image for post
Image for post

Introduction

Intended Audience

Why Should I Write Tests?

OK, Let’s Write a Test

use App\Services\NewsletterSubscriptionService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class NewsletterSubscriptionController extends Controller
{
/**
* Store a new newsletter subscriber.
*
* @param Request $request
* @return JsonResponse
*/
public function store(Request $request): JsonResponse
{
$service = NewsletterSubscriptionService();
$service->handle($request->email);
return response()->json(['success' => true]);
}
}
class NewsletterSubscriptionControllerTest extends TestCase
{
/** @test */
public function success_response_is_returned()
{
$this->postJson('/newsletter/subscriptions', [
'email' => 'mail@ashallendesign.co.uk',
])->assertExactJson([
'success' => true,
]);
}
}

Now, Let’s Write a Better Test

What’s The Problem?

How Can We Fix The Problem?

use App\Services\NewsletterSubscriptionService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class NewsletterSubscriptionController extends Controller
{
/**
* Store a new newsletter subscriber.
*
* @param Request $request
* @param NewsletterSubscriptionService $service
* @return JsonResponse
*/
public function store(Request $request, NewsletterSubscriptionService $service): JsonResponse
{
$service->handle($request->email);
return response()->json(['success' => true]);
}
}
class NewsletterSubscriptionControllerTest extends TestCase
{
/** @test */
public function success_response_is_returned()
{
// Create the mock of the service class.
$mock = Mockery::mock(NewsletterSubscriptionService::class)->makePartial();
// Set the mocked class' expectations.
$mock->shouldReceive('handle')->once()->withArgs(['mail@ashallendesign'])->andReturnNull();
// Add this mock to the service container to take the service class' place. app()->instance(NewsletterSubscriptionService::class, $mock); $this->postJson('/newsletter/subscriptions', [
'email' => 'mail@ashallendesign.co.uk',
])->assertExactJson([
'success' => true,
]);
}
}

Bonus Tip

use App\Services\NewsletterSubscriptionService; 
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class NewsletterSubscriptionController extends Controller
{
/**
* Store a new newsletter subscriber.
*
* @param Request $request
* @return JsonResponse
*/
public function store(Request $request): JsonResponse
{
$service = resolve(NewsletterSubscriptionService::class);
$service->handle($request->email);
return response()->json(['success' => true]);
}
}

Conclusion

I’m a Laravel web developer based in the UK. I specialise in building websites and systems for small businesses to help them grow and increase their sales.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store