未加星标

TDD your API with Symfony and PHPUnit

字体大小 | |
[开发(php) 所属分类 开发(php) | 发布者 店小二03 | 时间 2016 | 作者 红领巾 ] 0人收藏点击收藏

At Lakion we truly believe in TDD approach. We are convinced that rapid development can not be achieved without proper testing and SOLID code. We always start with defining our needs and writing scenarios, specifications or tests that reflect them. Thanks to this approach, we get exactly what we need and tests are protecting us from regressions.

Our Open Source project - Sylius is developed using the Full-Stack BDD methodology. You should always choose a tool that is the most suitable for the job. Behat and phpspec don't have many secrets for us because we are using them on a daily basis. Nevertheless, with one of big projects we have decided to add another tool to our TDD toolbelt. We have come up with a very simple but useful PHPUnit test case for testing APIs. - ApiTestCase .

Why ApiTestCase?

We had to develop several Symfony applications communicating with each other via JSON API . Multiple developers were working on them simultaneously. Yet they had to implemented as if everything existed and worked already. So how do you do that? We had to define contracts - requests and expected responses. We decided to put the latter in simple .json files and use them for our TDD workflow. Then we just had to prepare a request in our test suite, send the request and compare the result with our expectations. What is more we could agree on a specific JSON response of the other app, define it in a separate file and easily mock the responses from our own and third-party services. That allowed us to develop the applications in parallel and without blocking each other.

To improve the developer experience when working with the ApiTestCase, we have extended the basic Symfony WebTestCase with PHP-Matcher , SymfonyMockerContainer and Alice libraries. The first one allows to assert unpredictable values, such as object ids, current dates and etc. The second one simplifies the mocking process. The third one allows you to load sample data with ease. Big "Thank you" to the community for these excellent tools!

But how does it work in practice? Let me show you #TheLakionWay.

Rapid TDD API Development with Lionframe and ApiTestCase

Let's assume that we are creating a very simple e-commerce catalog API. How quickly we can create a full CRUD API following the Test-Driven-Development workflow? Have a look!

Set Up The Project

You can do all this with plain Symfony but we have prepared a slightly modified Symfony-Standard Edition, which has all the API goodies pre-installed. We call itLionframe. It allows you to develop powerful REST APIs with ease, while supporting the best practices.

composer create-project lakion/lionframe project/ 0.3.0 --prefer-dist cd project/

You can see example use of Lionframe and ApiTestCase in the DemoBundle directory but let's create our own API. We should start from removing the DemoBundle:

Delete the ``src/DemoBundle`` directory; Edit ``app/config/api.yml`` and remove the first six lines: sylius_resource: resources: acme.post: driver: doctrine/orm classes: model: DemoBundle\Entity\Post Remove `new DemoBundle\DemoBundle()` reference in ``app/AppKernel.php``; Remove routing importing in ``app/config/routing.yml``; acme_demo: resource: "@DemoBundle/Resources/config/routing.yml" prefix: /

Finally, let's create an empty database:

app/console doctrine:database:create

That's it, we can get our hands dirty with some code!

Write Your Test!

With our needs defined we can write our first test. Let's start with a creation step. To create a product we need to provide the following data:

{ "name": "Star Wars T-Shirt", "sku": "SWTS", "price": 50 }

And send it to /products/ endpoint. The test should be placed under src/AppBundle/Tests/Controller/ directory in the ProductApiTest.php file and looks like this:

This test will ensure that the data we sent will result in a proper object creation. To check the response we should define our expectation in src/AppBundle/Tests/Responses/Expected/products/create_response.json file.

{ "id": @integer@, "name": "Star Wars T-Shirt", "sku": "SWTS", "price": 50 }

Let's run our test now. According to the TDD worfklow, we should see some red color:

bin/phpunit Defining Expected Responses

We will use a Product entity with the following fields:

Id (integer) Name (string) Sku (string) Price (integer) Let's Make It Green

It's high time to write some code, isn't it? If you know Symfony basics, you will know that to turn this test green we will need following things:

Product entity Controller Routing

Of course, it is super simple to implement that in raw Symfony but who has the time to do the same thing all over again? We need to be rapid! That's where Lionframe comes into play.

Symfony has a simple generate command, which will create the entity for us. We suggest using the yml format. The class will use AppBundle:Product as shortcut name. Remember that id field will be generated by default. Run:

app/console generate:doctrine:entity

You should see something like this output below, just follow instructions:

Welcome to the Doctrine2 entity generator This command helps you generate Doctrine2 entities. First, you need to give the entity name you want to generate. You must use the shortcut notation like AcmeBlogBundle:Post. The Entity shortcut name: AppBundle:Product Determine the format to use for the mapping information. Configuration format (yml, xml, php, or annotation) [annotation]: yml Instead of starting with a blank entity, you can add some fields now. Note that the primary key will be added automatically (named id). Available types: array, simple_array, json_array, object, boolean, integer, smallint, bigint, string, text, datetime, datetimetz, date, time, decimal, float, binary, blob, guid. New field name (press <return> to stop adding fields): name Field type [string]: Field length [255]: New field name (press <return> to stop adding fields): sku Field type [string]: Field length [255]: New field name (press <return> to stop adding fields): price Field type [string]: integer New field name (press <return> to stop adding fields): Do you want to generate an empty repository class [no]? Summary before generation You are going to generate a "AppBundle:Product" Doctrine2 entity using the "yml" format. Do you confirm generation [yes]? Entity generation Generating the entity code: OK You can now start using the generated code!

Finally, you can create your database schema:

app/console doctrine:schema:create

At this point we should create a controller and define proper routing. You do not have to bother with tedious writing of repetitive code for standard CRUD actions.

Let's finally put Lionframe to work. Register your new entity as a Sylius resource in app/config/api.yml

sylius_resource: resources: app.product: classes: model: AppBundle\Entity\Product

And add this routing configuration to app/config/routing.yml :

app_product_api: resource: app.product type: sylius.api

Now run your tests again.

bin/phpunit

What color do you see? You can try it yourself. Spin up the built-in server and do some requests:

php app/console server:run

Create a product via CURL:

curl -i -X POST -H "Content-Type: application/json" -d '{"name": "Awesome Mug", "sku": "MUG-492", "price": 499}' http://127.0.0.1:8000/products/ Refactor

In this case, Lionframe with SyliusResourceBundle inside takes care of all the heavy-lifting but if you prefer to implement controllers on your own, then you could go now and refactor your code and ApiTestCase will ensure everything still works. This workflow allows to maintain very high quality of code in the project and makes your life as a developer much easier.

While this examples shows REST-style CRUD, keep in mind that you can test pretty much any type of API.

Not a fan of JSON?

We got you covered. ApiTestCase supports XML too. Because necessity is the mother of invention, our colleague @Arminek implemented XML support. Testing SOAP APIs or any other that uses XML messages have never been so easy!

Summary

There is no rapid development without testing. Quoting Uncle Bob: "The only way to go fast is to go well". You can develop something really quickly but without testing the technical debt will slow you down very soon and every change will be very costly. ApiTestCase allows you to change your API very easily: Change the test or expected response, see red color and then worry only about making it green again. That's why we have created ApiTestCase and Lionframe. These two will be your best buddies in the world of API development and save you a lot of time.

Useful Documentation Links:

本文开发(php)相关术语:php代码审计工具 php开发工程师 移动开发者大会 移动互联网开发 web开发工程师 软件开发流程 软件开发工程师

主题: PHPXMLRESTSOACU
分页:12
转载请注明
本文标题:TDD your API with Symfony and PHPUnit
本站链接:http://www.codesec.net/view/482190.html
分享请点击:


1.凡CodeSecTeam转载的文章,均出自其它媒体或其他官网介绍,目的在于传递更多的信息,并不代表本站赞同其观点和其真实性负责;
2.转载的文章仅代表原创作者观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,本站对该文以及其中全部或者部分内容、文字的真实性、完整性、及时性,不作出任何保证或承若;
3.如本站转载稿涉及版权等问题,请作者及时联系本站,我们会及时处理。
登录后可拥有收藏文章、关注作者等权限...
技术大类 技术大类 | 开发(php) | 评论(0) | 阅读(37)