Work begins with testing

In the life of each developer, there comes a moment when he thinks about creating a test component for his brainchild. Get better - in the life of every good developer. When you are a junior and do not bear special responsibility, you have the right to a lot of mistakes and you can fix them at any time. You are not responsible for the product that you create and do not have the motivation to spend an extra minute on re-checking the generated code. “Oh, nothing, this joint cannot be reproduced”, “it seems that this thing works”, “well, at least, it does what it needs” - if you want to outgrow the level of programming nursery, then you will have to negate each of these thoughts.

With the development of your own programming experience, you have new, more and more cool / large clients. From some you will even be delighted (from all, if you are just lucky) - and people are good, and pay generously, and not picky about the problems. Let's consider one such simple case (very simple, but the main thing is behind it) of creating a form handler from a programmer who does not know the trouble.

So, a simple task arrived - to write a form handler. The goal is to accept bids from customers for the purchase of bricks. The customer is large, engaged in large deliveries of bricks in bulk (for example, in the amount of 500,000 rubles or more - in order to feel at least some level of responsibility for what is happening). The competition is mad - customers can quickly go to the supplier of bricks, if you do not answer within 24 hours.

Our programmer was told that the client’s data should be saved from the form - representative’s full name, telephone number, customer’s company name, order quantity and an optional order description field. Having flipped brains, the simplest form with standard fields for the front of the site was quickly created:

the form

Data from the form is sent by an AJAX request, without reloading the page. Next, the programmer takes on the design of the form handler and he needs to cope with a rather trivial task - add entries to the already existing Orders table for a new client and send a letter to the customer with an alert for the new client.

simple insert code

The form works, the data is successfully saved, the customer is satisfied. But suddenly an angry call comes from the customer “so they say, and so, the order was received - the millionaire company wants to buy all the bricks from me, but the phone number did not come from the form and now how to contact them?! Tomorrow they will find another supplier! How so what did you do ?! It's your fault ... ”. The customer breaks and throws, minus nerves, minus trust and minus respect. The situation is extremely standard for the junior - the absence of any validation and testing of incoming data from the form. The first task (validation) is solved very simply, by adding validation rules:


Henceforth, the client of the site will indicate only the correct data we need for further processing. At the same stage, the developer comes to the idea of ​​the need to test the code to further avoid such an awkward situation. For example, testing the last name field will look like this (to simplify the basic example, csrf protection is disabled):

missing field test

We know that in the absence of this field, the code should return a response with an error and the 400 status that we have written. Such testing methods are written for each specific situation ( or specific field validation, it all depends on the tasks and developer’s imagination).

But is there any other way of working out other than “I did, and now I will check”? We first write the code, stumble on the shoals of execution, correct, and then remember about the tests. This approach can go sideways for us and our customer, given the lost multimillion-dollar client (although theoretically, but all such clients). And here I wondered - what if we start the logic of creating an application from the opposite end - first we will present the requirements for the “performer” and then make it meet these requirements? Let's try.

We will leave the task as before, change only the approach to it. We need to write a form handler with fields fio, phone, corp, quant and content. The result of a successful execution is status 200, adding a field to the Order with the message “ok” and returning the data for the entry made, the remaining options are status 400 and a list of errors.

First of all, we need to write a test method for validly filling out the form data:

valid method

Next, we create the necessary route and controller method (while it is empty). If we run the check now, it is quite expected that we will get an error. Validation of valid data filling is not all that we need. Now we start testing the validation of form fields. Determine which fields are required - fio, phone, corp, quant and add a method to check (comment is not required):


The form handler will simply have to check for incoming data fio, phone, corp, quant. Since we have removed all the required fields from the request, an error in errors should be returned for each of them. If at least one of them is not - the problem of execution. If desired, you can add a message check, as was done previously (check for “ok”).
We make a check for the minimum length of the fio, phone and corp fields (the same will be done for the maximum length and for invalid characters in these fields).

minimum length

Our checks are decorated, you can run and check

result of checking

Perfect. Our application crashed in 5 of 5 tests. Our further goal is to walk through test methods that set invalid values ​​to fields, and form validation rules for incoming data. The logic is something like this: the fio field cannot be empty; length not less than 3 and not more than 120; This is a string with a set of characters allowed in the name (letter, hyphen, indent). The result of this logic for all fields:


In response, in the case of a file, a list of errors errors is added that correspond to each “problem” field. This will help us to check specific fields for validation (assertJsonStructure in the test file). Next, we add a method for validation checking and get the final version:

final method

And finally, we can check how our script performs testing (recall, there were 5 files in 5 tests).


As you can see, all the tests passed successfully and only one record was entered into the database (since only one method was configured for valid operation).

the result is entered into the database

What are the conclusions? Developing an application, starting with tests, is a better option than the usual writing of functionality. The need to get from the method only what is needed is comparable to army discipline - the code does exactly what you require from it, not one step to the side. However, this approach has a negative side (albeit controversial) - the fact is that writing additional functionality (which is testing) also takes a part of the time allotted for the development of the project. As for me, the choice is clear: a good programmer must write tests, and starting from the test functionality helps to write a well-working and reliable project. I will try to use it in something less trivial.

Also popular now: