Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

Sorry, you do not have permission to ask a question, You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please type your username.

Please type your E-Mail.

Please choose an appropriate title for the post.

Please choose the appropriate section so your post can be easily searched.

Please choose suitable Keywords Ex: post, video.

Browse

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise Logo Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise Logo

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise Navigation

  • Home
  • About Us
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • About Us
  • Contact Us
Home/ Questions/Q 1404

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise Latest Questions

Author
  • 62k
Author
Asked: November 25, 20242024-11-25T07:51:08+00:00 2024-11-25T07:51:08+00:00

Testing Fat Laravel Controllers – Pt. 1

  • 62k

Many new products launching out there don't embrace a TDD approach. It's the norm that code is pushed to production for months until the MVP is ready or launch is due. That's when the Project Managers decide, it is time, for testing, only to realize that their codebase has controllers that look like this bad boy:

And that's not the whole controller :D. It's pretty hard to refactor code like this or add/change features without breaking things. It's even harder to test it, but that's just how things are.

Breaking down the feature we're testing into steps, we have:

  • A logged-in user uploads a photo
  • This photo needs to be taken from a mobile device and contain geolocation data
  • Store the photo into a filesystem according to its creation date
  • Extract the state, city, road, and other geographic details from it
  • Store the Photo model in the database with the extracted data
  • Update the users' XP and fire a few events

Pretty long for a controller public method, right? Right. Let's start by testing the happy path first.

Setting up

From this initial set up we notice that strange $this->imagePath property. Why do we need it? Here's what's happening: the feature requires geo-tagged images, they need to contain location data, which we found was difficult to create using Laravel UploadedFile fakes. So we used an image for which we know the location attributes, and we can test against them.

Another thing that's happening is that, in local/development environments, the controller does not store the images in the storage directory, it stores them directly in public. That makes it hard (impossible?) to test according to the usual Laravel way with the Storage facade. So we mimic the same approach. Keep a small testing image, less than 1 KB, run the tests, and then delete it manually at the end.

Onto the first test method, we do the usual world-building: fake the Storage, fake the Events, fix the Carbon test time for stable tests, and create and log in a user.

Variables to test against

The next step is to create some “input” values that we'll assert later. We use the test image and make an UploadedFile fake out of it. We know the value of the other variables like $latitude, $longitude, $address, etc. beforehand, and that is what our controller should save after parsing the image.

Notice the strange assignments of city, state, and country. Those are needed because the calls to $this->checkCountry($addressArray); on the PhotosController will persist a new Country object if it doesn't find one.

The other variables are used to determine the directory where the image will be stored, as well as the name used to reference it elsewhere in the app. The way we calculate the directory using $datetime is not quite the same as the one used in the PhotosController, and it doesn't have to be. We want to test the logic behind it, not every single detail we encounter so that we allow the implementation to change, but the logic can remain the same.

The test

Before we post a request to the controller, we do a small sanity check with those three assertions about the user's XP, has_uploaded, and total_images. Those could be omitted, but more often than not it happens that these values are wrong from the start, and we're missing something in our world-building phase. When we assert them later we'll get passing tests, but we might not be testing anything, so it's nice to have them.

After posting a request, we immediately assert that it returns with a 200 status code, and the correct response message. Then, we assert that the image exists in the desired location, and it has the right properties, like height and width.

Sigh. That was long, but much-needed :D. It's appropriate that we update the $user model by calling $user->refresh(), because we're making a request, and the framework has no way of knowing that this $user is being updated during that request lifecycle.

After testing that those values about user XP, total_images, etc. are incremented properly, we assert that the Photo model has been persisted, and retrieve it to do some drilling. We assert every single property that is assigned to this model from the controller, and while that may feel too much, it offers a great deal of peace of mind.

Testing fired events and closing

Event testing is super simple. There are two events fired, and we test them in detail. Every argument they receive should match our expected values. And that's it.

Finally, we delete the image we uploaded during our test to the public directory, to clean up.

And the other not-so-happy paths?

Yes, we haven't tested the other aspects of this post request. What if an unauthenticated user can wreak havoc on the app? What if they upload a PDF file? Are we asserting that all those exceptions are thrown when they should? Does it upload the photo to AWS S3 on production environments?
We need a whole new post about them. Till then, bye.

The code used for illustration is taken from the OpenLitterMap project. They're doing a great job creating the world's most advanced open database on litter, brands & plastic pollution. The project is open-sourced and would love your contributions, both as users and developers.

laravelphptestingwebdev
  • 0 0 Answers
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

Sidebar

Ask A Question

Stats

  • Questions 4k
  • Answers 0
  • Best Answers 0
  • Users 2k
  • Popular
  • Answers
  • Author

    ES6 - A beginners guide - Template Literals

    • 0 Answers
  • Author

    Understanding Higher Order Functions in JavaScript.

    • 0 Answers
  • Author

    Build a custom video chat app with Daily and Vue.js

    • 0 Answers

Top Members

Samantha Carter

Samantha Carter

  • 0 Questions
  • 20 Points
Begginer
Ella Lewis

Ella Lewis

  • 0 Questions
  • 20 Points
Begginer
Isaac Anderson

Isaac Anderson

  • 0 Questions
  • 20 Points
Begginer

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help

Footer

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise

Querify Question Shop: Explore, ask, and connect. Join our vibrant Q&A community today!

About Us

  • About Us
  • Contact Us
  • All Users

Legal Stuff

  • Terms of Use
  • Privacy Policy
  • Cookie Policy

Help

  • Knowledge Base
  • Support

Follow

© 2022 Querify Question. All Rights Reserved

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.