Archive | Web development RSS feed for this section

Testing email component in CakePHP 2.1.x

14 Oct

Are you still sending yourself emails when you run test cases? I was.

Being relatively new to TDD this took a while to get my head around, but using “mocks” has proven to be really useful.

I’ll focus on the CakeEmail class in CakePHP 2.1.x as this proved most useful when writing test cases for Copify (we send _alot_ of emails!)

Here’s what one of our model methods looked like originally (before we had a test case).

When we started writing tests for other areas of the application which used this method, it fired an email.

To get round this, we had to mock the CakeEmail component. This also means you can test it is doing what it is supposed to be.

So to test this, we first need to make a change to the method itself:

Now, we can mock the CakeEmail class and test to ensure each part of our model method does what it should:

PHP and big file uploads: The empty $_POST array

1 Dec

The problem

So you’ve got your nice form, and want to allow users to attach a file. If the user tries to upload a file which exceeds the ‘post_max_size’ value in php.ini then WHAMMY…the entire $_POST variable will be empty.

This is a massive headache in terms of UX, your user has just spent 5 minutes entering information and simply because they tried to attach a 4Tb file then all this is lost. Validating the size of the file they attach is not the issue, the issue is that if the upload is part of a form with other text fields then their input will be lost.

The solution

First off, lets get the current value for ‘post_max_size’ and ‘upload_max_filesize’ from php.ini.

upload_max_filesize

upload_max_filesize

post_max_size

As you can see, my post_max_size is 20Mb and my upload_max_filesize is 10Mb.

Why are they different? Well, anything over 10Mb will upload but will return a decent error you can catch, but if a user tries to upload a file over 20Mb then the internet explodes and PHP simply dumps the whole lot, $_POST will be empty, as will $_FILES, $_REQUEST etc.

How this would look to the user uploading 15mb file

How this would look to the user uploading 15mb file

How this would look to the user uploading 15mb file

 

How this would look to the user uploading 25mb file

How this would look to the user uploading 25mb file

How this would look to the user uploading 25mb file

 

As you can see, if post_max_size is exceeded (the second screenshot), all the $_POST data is lost and the user has to start again.

One solution to this would be to have 2 separate forms, or split up the steps in the process so the file upload is on a separate page.

However there is a better solution: Ajax.

This approach uses two separate forms but we do it on the same page in such a way the UX is seamless.

  1. When the user clicks “Save and Continue” we submit form 1 (just the text/select fields) via ajax as a serialized array
  2. Validate it on the server and return a JSON array of info (such as: did it validate? if there are errors what are they? etc.)
  3. If it does validate, save it in a session
  4. Check the response client side, and if ok we submit form 2 (just the files) the usual way

Here’s how it looks.

The HTML for the forms

The JS (I’m using jQuery)

My code on the server validates the data from the text fields, saves it to a session, and returns a JSON object. If the validation fails it returns something like this.

We can use the response to show errors BEFORE the form with the files is submitted (the normal way).

Validation errors, used a modal because i'm hip

Validation errors, used a modal because i'm hip

If the response in the JSON is ‘success’ then we simply submit the second form as normal. If the file/s still exceed the post_max_size then at least the previous text input is on the session and can be used to populate the fields again.

How this would look to the user uploading 50mb file

Huge upload, $_POST is lost but we have the text fields in the session

 

The worlds most basic example of Unit Testing

12 Oct

1. In my head, I know what I want a method to do before I even write it, so I write a test that will pass if the code (that I write in step 2) works. In this case it is a basic method in one of my Models.

My fixture has 5 jobs already, I expect the next job to have an ID of 6 and a cost of 18.00

 

2. To make the test pass, here is my REAL method that I add to my model….

 

This just saves the job, the passed arg is an array like the one in the test (or at least I hope it is!)

 

3. Now lets run the test…

 

My test passes - my code does what I had in my head (saves a job)

 

4. Some other guy on the team changes some code…

 

Someone else on the team makes some weird change, probably high on meow

 

5. Looking at the change, it won’t work. The passed arg IS an array, so it will throw an exception. But my original test will catch the fact that this method does not work anymore, otherwise this bug could have gone unnoticed.

 

Before going live with these changes we would run all the tests, in this case, the app doesn't work!

 

From the failed test, you can even see which line of code is failing.

Obviously if you have not written a test for something it can not fail, so being thorough and making sure any bit of functionality has been tested its easy to catch problems and fix bugs.

And if you’re using Git, you can even see who broke the project. Then take it in turns to beat the developer around the head with a blunt instrument.

The worlds most basic summary

Ask yourself “The code I am about to write, what should it do/not do” – then write a test that covers any conceivable eventualities FIRST. Then write the real code to make the test pass.

 

 

Web Projects – An infographic

28 Sep

Info-graphics are all the rage. So I did very complicated one which demonstrates how the average web project  progresses over time.

 

...

 

 

Mistakes and lessons learned building Reddit

29 Jan

Reddit is a big site (in terms of traffic and data storage)  built by some guys in the US, one of their former developers talks openly about some of the issues they have had to overcome.


Lessons Learned while at Reddit from Carsonified on Vimeo.