{"id":356728,"date":"2024-05-20T23:35:46","date_gmt":"2024-05-20T23:35:46","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=356728"},"modified":"-0001-11-30T00:00:00","modified_gmt":"2024-05-20T23:35:46","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=356728","title":{"rendered":"<span>\u041f\u0438\u0448\u0435\u043c \u0410\u041f\u0418 \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u044b \u043d\u0430 Python \u043f\u043e \u0448\u0430\u0433\u0430\u043c<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/506\/e70\/4db\/506e704db3223917b774635cec89018c.png\" width=\"1024\" height=\"1024\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/506\/e70\/4db\/506e704db3223917b774635cec89018c.png\"\/><\/figure>\n<p>\u041c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u0410\u043b\u0435\u043a\u0441\u0435\u0439. \u042f \u044f\u0432\u043b\u044f\u044e\u0441\u044c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0441\u0442\u043e\u043c \u043f\u043e \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. \u041f\u0438\u0448\u0443 \u043a\u0430\u043a UI \u0442\u0435\u0441\u0442\u044b \u043d\u0430 \u0441\u0435\u043b\u0435\u043d\u0438\u0443\u043c\u0435, \u0442\u0430\u043a \u0438 \u043f\u043e\u043a\u0440\u044b\u0432\u0430\u044e \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0435 REST API.\u00a0 \u0414\u0430\u043d\u043d\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u043e\u043c \u0438 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0435\u0437\u043d\u0430 \u043a\u0430\u043a \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0449\u0438\u043c, \u0442\u0430\u043a \u0438 \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0449\u0438\u043a\u0430\u043c \u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0442\u043e\u0440\u0430\u043c. \u041d\u043e \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u043b\u0435\u0437\u043d\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c \u0438 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0441\u0442\u0430\u043c \u0438\u0437 \u0441\u043c\u0435\u0436\u043d\u044b\u0445 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0439. \u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u043f\u043e\u0448\u0430\u0433\u043e\u0432\u043e \u043f\u043e\u043a\u0440\u043e\u0435\u043c \u0442\u0435\u0441\u0442\u0430\u043c\u0438 REST API\u00a0 <a href=\"https:\/\/restful-api.dev\/\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/restful-api.dev<\/u><\/a> \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 GET, POST, PUT, DELETE. \u041f\u043e\u0434\u0445\u043e\u0434, \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u0432 \u0441\u0442\u0430\u0442\u044c\u0435, \u044f \u0441\u0430\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e \u043d\u0430 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435.<\/p>\n<h3>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0441\u0442\u0430\u0442\u044c\u0438<\/h3>\n<ol>\n<li>\n<p><strong>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438<\/strong><\/p>\n<\/li>\n<li>\n<p><strong>\u041d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432:<br \/><\/strong><\/p>\n<ol>\n<li>\n<p>\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u00a0\u0441\u0438\u0441\u0442\u0435\u043c\u0435 \u0442\u0435\u0441\u0442\u043e\u0432<\/p>\n<\/li>\n<li>\n<p>\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/p>\n<\/li>\n<li>\n<p>\u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0410\u041f\u0418 \u043a\u043b\u0438\u0435\u043d\u0442\u0430<\/p>\n<\/li>\n<li>\n<p>\u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430<\/p>\n<\/li>\n<li>\n<p>\u043a\u043e\u0434 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430<\/p>\n<\/li>\n<li>\n<p>\u0442\u0435\u0441\u0442\u044b \u043d\u0430 GET, POST, PUT, DELETE<\/p>\n<\/li>\n<\/ol>\n<\/li>\n<li>\n<p><strong>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/strong><\/p>\n<\/li>\n<\/ol>\n<h3>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438<\/h3>\n<ol>\n<li>\n<p><code>python 3.11.4<\/code><\/p>\n<\/li>\n<li>\n<p><code>pytest 7.4.0<\/code> &#8212; \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435:<a href=\"https:\/\/pytest-docs-ru.readthedocs.io\/ru\/latest\/usage.html\" rel=\"noopener noreferrer nofollow\"> <\/a><a href=\"https:\/\/pytest-docs-ru.readthedocs.io\/ru\/latest\/getting-started.html\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/pytest-docs-ru.readthedocs.io\/ru\/latest\/getting-started.html<\/u><\/a><\/p>\n<\/li>\n<li>\n<p><code>pydantic 2.3.0<\/code> &#8212; \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u043e\u0442\u0432\u0435\u0442\u0430. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435:<a href=\"https:\/\/docs.pydantic.dev\/\" rel=\"noopener noreferrer nofollow\"> <u>https:\/\/docs.pydantic.dev\/<\/u><\/a><\/p>\n<\/li>\n<li>\n<p><code>httpx 0.24.1<\/code> &#8212; \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435:<a href=\"https:\/\/www.python-httpx.org\/quickstart\/\" rel=\"noopener noreferrer nofollow\"> <u>https:\/\/www.python-httpx.org\/quickstart\/<\/u><\/a><\/p>\n<\/li>\n<li>\n<p>\u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0435 \u0410\u041f\u0418 &#8212; <a href=\"https:\/\/restful-api.dev\/\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/restful-api.dev<\/u><\/a><\/p>\n<\/li>\n<li>\n<p>\u0441\u0440\u0435\u0434\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 &#8212; <code>PyCharm<\/code>.<\/p>\n<\/li>\n<\/ol>\n<h3>\u041d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432<\/h3>\n<p>\u041f\u0435\u0440\u0435\u0434 \u0442\u0435\u043c, \u043a\u0430\u043a \u0447\u0442\u043e-\u0442\u043e \u043f\u0438\u0441\u0430\u0442\u044c, \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u043d\u0430\u0431\u043e\u0440 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0441\u043e\u0431\u043b\u044e\u0434\u0430\u0442\u044c \u0432 \u043d\u0430\u0448\u0435\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 \u0442\u0435\u0441\u0442\u043e\u0432, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e:<\/p>\n<ol>\n<li>\n<p>\u0438\u0434\u0435\u0439\u043d\u043e\u0441\u0442\u044c (\u043a\u0430\u0436\u0434\u044b\u0439 \u0442\u0435\u0441\u0442 \u0438\u043c\u0435\u0435\u0442 \u0447\u0435\u0442\u043a\u0443\u044e \u0438\u0434\u0435\u044e)<\/p>\n<\/li>\n<li>\n<p>\u0430\u0442\u043e\u043c\u0430\u0440\u043d\u043e\u0441\u0442\u044c \u0438\u0434\u0435\u0438 (\u0432 \u0442\u0435\u0441\u0442\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0430 \u0438\u0434\u0435\u044f)<\/p>\n<\/li>\n<li>\n<p>\u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u043e\u0442 \u0434\u0440\u0443\u0433\u0438\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 (\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0432 \u043e\u0434\u043d\u043e\u043c \u0442\u0435\u0441\u0442\u0435 \u043d\u0435 \u0432\u043b\u0438\u044f\u044e\u0442 \u043d\u0430 \u0434\u0440\u0443\u0433\u043e\u0439, \u0442\u0435\u0441\u0442\u044b \u043c\u043e\u0433\u0443\u0442 \u0438\u0434\u0442\u0438 \u0432 \u043b\u044e\u0431\u043e\u043c \u043f\u043e\u0440\u044f\u0434\u043a\u0435)<\/p>\n<\/li>\n<li>\n<p>\u0433\u0438\u0431\u043a\u043e\u0441\u0442\u044c \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 (\u0442\u0435\u0441\u0442\u044b \u043c\u043e\u0436\u043d\u043e \u043b\u0435\u0433\u043a\u043e \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438 \u043d\u0430 \u0434\u0440\u0443\u0433\u0443\u044e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0442\u0435\u043d\u0434 \u0438\u043b\u0438 \u0431\u044b\u0441\u0442\u0440\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0432 \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438)<\/p>\n<\/li>\n<\/ol>\n<p>\u0421\u043e\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u0435 \u044d\u0442\u0438\u0445 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043d\u0430\u043c \u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043d\u043e \u0438 \u043c\u0438\u043d\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043b\u0438\u0448\u043d\u0438\u0439 \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433.<\/p>\n<h3>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h3>\n<p>\u0421\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u043a\u0430\u0440\u043a\u0430\u0441 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0441 \u043f\u0430\u043f\u043a\u0430\u043c\u0438, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u043c\u0438:<\/p>\n<ul>\n<li>\n<p><strong>api<\/strong> &#8212; \u043a\u043b\u0430\u0441\u0441\u044b \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 api<\/p>\n<\/li>\n<li>\n<p><strong>logs<\/strong> &#8212; \u043b\u043e\u0433\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443<\/p>\n<\/li>\n<li>\n<p><strong>assertions<\/strong> &#8212; \u043a\u043b\u0430\u0441\u0441\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432<\/p>\n<\/li>\n<li>\n<p><strong>models<\/strong> &#8212; \u043c\u043e\u0434\u0435\u043b\u0438 pydantic \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0441\u0445\u0435\u043c \u043e\u0442\u0432\u0435\u0442\u0430<\/p>\n<\/li>\n<li>\n<p><strong>test_data<\/strong> &#8212; \u044d\u0442\u0430\u043b\u043e\u043d\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b json \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043e\u0442\u0432\u0435\u0442\u043e\u0432<\/p>\n<\/li>\n<li>\n<p><strong>tests<\/strong> &#8212; \u043a\u043b\u0430\u0441\u0441\u044b \u0441 \u0442\u0435\u0441\u0442\u0430\u043c\u0438<\/p>\n<\/li>\n<li>\n<p><strong>utilities<\/strong> &#8212; \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043a\u043b\u0430\u0441\u0441\u044b-\u0443\u0442\u0438\u043b\u0438\u0442\u044b (\u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 json \u0438.\u0442.\u0434)<\/p>\n<\/li>\n<\/ul>\n<p>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/649\/f50\/fce\/649f50fcebb70b4d8b61a370525ec8f0.png\" width=\"361\" height=\"257\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/649\/f50\/fce\/649f50fcebb70b4d8b61a370525ec8f0.png\"\/><\/figure>\n<p>\u041f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0442\u0430\u043a\u0436\u0435 \u0431\u044b\u043b\u0430 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u0430 \u043f\u0438\u0442\u043e\u043d\u043e\u0432\u0441\u043a\u0430\u044f \u043f\u0430\u043f\u043a\u0430<code>venv<\/code> (\u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 <a href=\"https:\/\/docs.python.org\/3\/library\/venv.html\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/docs.python.org\/3\/library\/venv.html<\/u><\/a>) \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a. \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u043a\u043e\u0440\u0435\u043d\u044c \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0444\u0430\u0439\u043b<code>requirements.txt<\/code><strong> <\/strong>\u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043e\u0439:<\/p>\n<pre><code class=\"python\">httpx==0.24.1 pytest==7.4.0 pydantic==2.3.0 python-dotenv==1.0.0<\/code><\/pre>\n<p>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 <code>pip install -r requirements.txt<\/code><\/p>\n<h3>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0410\u041f\u0418 \u043a\u043b\u0438\u0435\u043d\u0442\u0430<\/h3>\n<p>\u0412 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 httpx. \u0418\u0437 \u0444\u0438\u0447\u0435\u0439 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0441\u0435\u0441\u0441\u0438\u0438 (<a href=\"https:\/\/en.wikipedia.org\/wiki\/HTTP_persistent_connection\" rel=\"noopener noreferrer nofollow\"><u>HTTP connection pooling<\/u><\/a>) \u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b. \u041e\u0447\u0435\u043d\u044c \u043f\u043e\u043b\u0435\u0437\u043d\u0430 \u0432 \u043e\u0441\u0432\u043e\u0435\u043d\u0438\u0438. httpx \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043a\u043b\u0430\u0441\u0441 Client. \u041e\u043d \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u0442\u043a\u0440\u044b\u0442\u044c TCP \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0443\u0433\u043e\u0434\u043d\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u043d\u0435\u0433\u043e \u043e\u0434\u043d\u043e\u0433\u043e. \u042d\u0442\u043e \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0442 \u0432\u0440\u0435\u043c\u044f \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443.\u00a0<\/p>\n<p>\u041d\u0430\u0448 \u0410\u041f\u0418 \u043a\u043b\u0438\u0435\u043d\u0442 \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043f\u043e \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0443: \u0442\u0438\u043f \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u043f\u0443\u0442\u044c \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0433\u043e \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u0430.<\/p>\n<p>\u0412 \u043f\u0430\u043f\u043a\u0443<code>api<\/code>\u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0444\u0430\u0439\u043b<code>api_client.py<\/code><\/p>\n<pre><code class=\"python\">import os  from httpx import Client, Response  from utilities.logger_utils import logger   class ApiClient(Client):     \"\"\"     \u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0433\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0430 httpx.     \"\"\"      def __init__(self):         super().__init__(base_url=f\"https:\/\/{os.getenv('RESOURSE_URL')}\")      def request(self, method, url, **kwargs) -> Response:         \"\"\"         \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u043b\u043e\u0433\u0438\u043a\u0438 \u043c\u0435\u0442\u043e\u0434\u0430 httpx request \u0441 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u043c \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0442\u0438\u043f\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438 \u0435\u0433\u043e url,         \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u043b\u0438 \u043d\u0435\u0442 \u0437\u0430\u0434\u0430\u0435\u0442\u0441\u044f \u0432 \u0444\u0430\u0439\u043b\u0435 .env         :param method: \u043c\u0435\u0442\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c (POST, GET \u0438.\u0442.\u0434)         :param url: \u043f\u0443\u0442\u044c \u043d\u0430 \u0434\u043e\u043c\u0435\u043d\u0435, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441         \"\"\"          if eval(os.getenv(\"USE_LOGS\")):             logger.info(f'{method} {url}')         return super().request(method, url, **kwargs)<\/code><\/pre>\n<p>\u041d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u0432 \u0444\u0430\u0439\u043b<code>objects_api.py<\/code><\/p>\n<pre><code class=\"python\">from api import routes   def get_objects(client, *ids):     return client.get(routes.Routes.OBJECTS, params={'id': ids} if ids else None)   def get_object(client, obj_id):     return client.get(routes.Routes.OBJECTS_ITEM.format(obj_id))   def post_object(client, **kwargs):     return client.post(routes.Routes.OBJECTS, **kwargs)   def put_object(client, obj_id, **kwargs):     return client.put(routes.Routes.OBJECTS_ITEM.format(obj_id), **kwargs)   def delete_object(client, obj_id):     return client.delete(routes.Routes.OBJECTS_ITEM.format(obj_id)) <\/code><\/pre>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043a\u043b\u0430\u0441\u0441 \u0441 \u043f\u0443\u0442\u044f\u043c\u0438 \u0432\u043d\u0443\u0442\u0440\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0432 \u0444\u0430\u0439\u043b<code>routes.py<\/code><\/p>\n<pre><code class=\"python\">from enum import Enum   class Routes(str, Enum):     OBJECTS = '\/objects'     OBJECTS_ITEM = '\/objects\/{}'      def __str__(self) -> str:         return self.value<\/code><\/pre>\n<p>\u041f\u0435\u0440\u0435\u0434 \u0442\u0435\u043c, \u043a\u0430\u043a \u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0435\u0440\u0432\u044b\u0439 \u0442\u0435\u0441\u0442, \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u043a\u043e\u0440\u0435\u043d\u044c \u043f\u0440\u043e\u0435\u043a\u0442\u0430<code>conftest.py<\/code>, <code>.env<\/code> \u0444\u0430\u0439\u043b \u0438<code>pytest.ini<\/code>. \u041e\u043d\u0438 \u043d\u0443\u0436\u043d\u044b \u0434\u043b\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432 \u043d\u0430\u0448\u0435\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u0435.<\/p>\n<p>\u0424\u0430\u0439\u043b<code>conftest.py<\/code><\/p>\n<pre><code class=\"python\">import logging import os  from dotenv import load_dotenv  from utilities.logger_utils import logger   def pytest_configure(config):     # \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u043d\u0430 \u043a\u043e\u0440\u0435\u043d\u044c \u043f\u0440\u043e\u0435\u043a\u0442\u0430 (\u044d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043f\u0440\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u0443\u0442\u0438 \u043a \u0444\u0430\u0439\u043b\u0430\u043c)     os.chdir(os.path.dirname(os.path.abspath(__file__)))      # \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435-\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 \/.env     load_dotenv(dotenv_path=\".env\")      # \u0437\u0430\u0434\u0430\u0435\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043b\u043e\u0433\u0433\u0435\u0440\u0430     path = \"logs\/\"     os.makedirs(os.path.dirname(path), exist_ok=True)     file_handler = logging.FileHandler(path + \"\/info.log\", \"w\")     file_handler.setLevel(logging.INFO)     file_handler.setFormatter(logging.Formatter(\"%(lineno)d: %(asctime)s %(message)s\"))      # \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0439 \u043b\u043e\u0433\u0433\u0435\u0440     custom_logger = logging.getLogger(\"custom_loger\")     custom_logger.setLevel(logging.INFO)     custom_logger.addHandler(file_handler)   def pytest_runtest_setup(item):     logger.info(f\"{item.name}:\")<\/code><\/pre>\n<p>\u0424\u0430\u0439\u043b<code>.env<\/code><\/p>\n<pre><code class=\"python\">RESOURSE_URL=api.restful-api.dev USE_LOGS=True<\/code><\/pre>\n<p>\u0424\u0430\u0439\u043b<code>pytest.ini<\/code><\/p>\n<pre><code class=\"python\">[pytest] addopts =    --rootdir=.    -p no:logging<\/code><\/pre>\n<p>\u0412\u0441\u0435 \u0433\u043e\u0442\u043e\u0432\u043e \u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430. \u041f\u043e \u0438\u0442\u043e\u0433\u0443 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a06\/b0a\/f17\/a06b0af17717d7d0b943167b764e9ad4.png\" width=\"302\" height=\"447\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/a06\/b0a\/f17\/a06b0af17717d7d0b943167b764e9ad4.png\"\/><\/figure>\n<h3>\u041d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430<\/h3>\n<p>\u0421\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043a \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u043d\u0430\u0448\u0438\u0445 \u0442\u0435\u0441\u0442\u043e\u0432. \u041a\u0430\u0436\u0434\u044b\u0439 \u0442\u0435\u0441\u0442 \u0438\u043c\u0435\u0435\u0442 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0438 \u043d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b (\u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u043b\u043e\u0433\u0438\u043a\u0438 \u0441\u0430\u043c\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430). \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043d\u043e \u044d\u0442\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/p>\n<ol>\n<li>\n<p>\u041e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043a\u043e\u0434\u0430 \u043e\u0442\u0432\u0435\u0442\u0430 (\u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0439 \u0438 \u043f\u0440\u0438\u0448\u0435\u0434\u0448\u0438\u0439 \u043a\u043e\u0434).<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0441\u0445\u0435\u043c\u044b \u043e\u0442\u0432\u0435\u0442\u0430 (\u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0442\u0435\u043b\u0430 \u043e\u0442\u0432\u0435\u0442\u0430 \u0438 \u0442\u0438\u043f\u044b \u043f\u043e\u043b\u0435\u0439).<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0442\u0435\u043b\u0430 \u043e\u0442\u0432\u0435\u0442\u0430 \u0438 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438<\/p>\n<\/li>\n<\/ol>\n<p>1 \u0438 2\u00a0 \u043f\u0443\u043d\u043a\u0442\u044b \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0442.\u043a \u043b\u044e\u0431\u043e\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u0434\u0430\u0435\u0442 \u043d\u0430\u043c \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0439 \u043a\u043e\u0434 \u043e\u0442\u0432\u0435\u0442\u0430. \u0422\u0440\u0435\u0442\u0438\u0439 \u043f\u0443\u043d\u043a\u0442 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c, \u0435\u0441\u043b\u0438 \u0443 \u043e\u0442\u0432\u0435\u0442\u0430 \u0435\u0441\u0442\u044c \u0442\u0435\u043b\u043e (json). 4 \u043f\u0443\u043d\u043a\u0442 \u043f\u043e\u0434\u0440\u0430\u0437\u0443\u043c\u0435\u0432\u0430\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0441\u0442\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u043f\u043e\u043b\u0435\u0439 \u0432 \u0442\u0435\u043b\u0435 \u043e\u0442\u0432\u0435\u0442\u0430, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0438\u0434\u0435\u0438 \u043d\u0430\u0448\u0435\u0433\u043e \u0442\u0435\u0441\u0442\u0430. \u042d\u0442\u043e\u0442 \u043f\u0443\u043d\u043a\u0442 \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c, \u0435\u0441\u043b\u0438 \u0443 \u043e\u0442\u0432\u0435\u0442\u0430 \u0435\u0441\u0442\u044c \u0442\u0435\u043b\u043e.<\/p>\n<p>\u0414\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a 2, 3 \u0438 4 \u043f\u0443\u043d\u043a\u0442\u043e\u0432 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b assertion. \u0412 \u043f\u0430\u043f\u043a\u0443<code>assertions<\/code> \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043a\u043b\u0430\u0441\u0441<code>assertion_base.py<\/code><\/p>\n<pre><code class=\"python\">from typing import Type  from pydantic import BaseModel  from utilities.files_utils import read_json_test_data, read_json_common_response_data from utilities.json_utils import compare_json_left_in_right, remove_ids   class LogMsg:     \"\"\"     \u0411\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0435 \u043b\u043e\u0433\u043e\u0432 AssertionError. \u041a\u043e\u043d\u0441\u0442\u0440\u0443\u0438\u0440\u0443\u0435\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0432 \u0441\u0432\u043e\u0435 \u043f\u043e\u043b\u0435 _msg.     \"\"\"      def __init__(self, where, response):         self._msg = \"\"         self._response = response         self._where = where      def add_request_url(self):         \"\"\"         \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0431 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u043c \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u0437\u0430\u043f\u0440\u043e\u0441\u0435         \"\"\"         self._msg += f\"\u0421\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 (url, query params, \u0442\u0435\u043b\u043e):\\n\" \\                      f\"\\tURL: {self._response.request.url}\\n\"         self._msg += f\"\\tmethod: {self._response.request.method}\\n\"         self._msg += f\"\\theaders: {dict(self._response.request.headers)}\\n\"         if hasattr(self._response.request, 'params') and self._response.request.params:             self._msg += f\"\\tquery params: {self._response.request.params}\\n\"         else:             self._msg += f\"\\tquery params:\\n\"         if hasattr(self._response.request, 'content') and self._response.request.read():             self._msg += f\"\\tbody: {self._response.request.read()}\\n\"         else:             self._msg += f\"\\tbody:\\n\"         return self      def add_response_info(self):         \"\"\"         \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u043c \u0442\u0435\u043b\u0430 \u043e\u0442\u0432\u0435\u0442\u0430         \"\"\"         self._msg += f\"\u0422\u0435\u043b\u043e \u043e\u0442\u0432\u0435\u0442\u0430:\\n\\t{self._response.content}\\n\"         return self      def add_error_info(self, text):         if text:             self._msg += f\"\\n{text}\\n\"         else:             self._msg += \"\\n\"         return self      def get_message(self):         return self._msg   class BodyLogMsg(LogMsg):     \"\"\"     \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0432 \u043b\u043e\u0433\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a \u0442\u0435\u043b\u0430 \u043e\u0442\u0432\u0435\u0442\u0430.     \"\"\"      def __init__(self, response):         super().__init__('\u0412 \u0422\u0415\u041b\u0415 \u041e\u0422\u0412\u0415\u0422\u0410', response)      def add_compare_result(self, diff):         \"\"\"         \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0433\u043e json \u0441 \u044d\u0442\u0430\u043b\u043e\u043d\u043e\u043c         :param diff: \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043f\u043e\u043b\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0441\u043b\u0435 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u0438\u043c\u0435\u044e\u0442 \u0440\u0430\u0437\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f         \"\"\"         self._msg += f\"{self._where} \u0432 json \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043f\u043e\u043b\u044f \u043d\u0435 \u0441\u043e\u0432\u043f\u0430\u043b\u0438 \u0441 \u044d\u0442\u0430\u043b\u043e\u043d\u043e\u043c:\\n\"         for key, value in diff.items():             self._msg += f\"\u043a\u043b\u044e\u0447: {value['path']}\\n\\t\\texpected: {value['expected']} \\n\\t\\tactual: {value['actual']}\\n\"         return self   class CodeLogMsg(LogMsg):     \"\"\"     \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0432 \u043b\u043e\u0433\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043a\u043e\u0434\u0430 \u043e\u0442\u0432\u0435\u0442\u0430.     \"\"\"      def __init__(self, response):         super().__init__('\u0412 \u041a\u041e\u0414\u0415 \u041e\u0422\u0412\u0415\u0422\u0410', response)      def add_compare_result(self, exp, act):         \"\"\"         \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e\u0431 \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u043e\u043c \u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0439 \u043a\u043e\u0434\u0435         :param exp: \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0439 \u043a\u043e\u0434         :param act: \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u043a\u043e\u0434         \"\"\"         self._msg += f\"{self._where} \\n\\t\u043e\u0436\u0438\u0434\u0430\u043b\u0441\u044f \u043a\u043e\u0434: {exp}\\n\\t\u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u043a\u043e\u0434: {act}\\n\"         return self   class BodyValueLogMsg(LogMsg):     def __init__(self, response):         super().__init__('\u0412 \u0422\u0415\u041b\u0415 \u041e\u0422\u0412\u0415\u0422\u0410', response)      def add_compare_result(self, exp, act):         \"\"\"         \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0432 \u0442\u0435\u043b\u0435 \u043e\u0442\u0432\u0435\u0442\u0430         :param exp: \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435         :param act: \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435         \"\"\"         self._msg += f\"\\texptected: {exp}\\n\\tactual: {act}\\n\"         return self   def assert_status_code(response, expected_code):     \"\"\"     \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u0442 \u043a\u043e\u0434 \u043e\u0442\u0432\u0435\u0442\u0430 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0441 \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u043c     :param response: \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043e\u0442\u0432\u0435\u0442     :param expected_code: \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0439 \u043a\u043e\u0434 \u043e\u0442\u0432\u0435\u0442\u0430     :raises AssertionError: \u0435\u0441\u043b\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043d\u0435 \u0441\u043e\u0432\u043f\u0430\u043b\u0438     \"\"\"     assert expected_code == response.status_code, CodeLogMsg(response) \\         .add_compare_result(expected_code, response.status_code) \\         .add_request_url() \\         .add_response_info() \\         .get_message()   def assert_schema(response, model: Type[BaseModel]):     \"\"\"     \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0442\u0435\u043b\u043e \u043e\u0442\u0432\u0435\u0442\u0430 \u043d\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0435 \u0435\u0433\u043e \u0441\u0445\u0435\u043c\u0435 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0430\u043c\u0438 pydantic     :param response: \u043e\u0442\u0432\u0435\u0442 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430     :param model: \u043c\u043e\u0434\u0435\u043b\u044c, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c\u0441\u044f \u0441\u0445\u0435\u043c\u0430 json     :raises ValidationError: \u0435\u0441\u043b\u0438 \u0442\u0435\u043b\u043e \u043e\u0442\u0432\u0435\u0442\u0430 \u043d\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0441\u0445\u0435\u043c\u0435     \"\"\"     body = response.json()     if isinstance(body, list):         for item in body:             model.model_validate(item, strict=True)     else:         model.model_validate(body, strict=True)   def assert_left_in_right_json(response, exp_json, actual_json):     \"\"\"     \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0447\u0442\u043e \u0432\u0441\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u0435\u0439 exp_json \u0440\u0430\u0432\u043d\u044b \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c \u043f\u043e\u043b\u0435\u0439 \u0432 actual_json     :param response: \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u043e\u0442\u0432\u0435\u0442 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430     :param exp_json: \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0439 \u044d\u0442\u0430\u043b\u043e\u043d\u043d\u044b\u0439 json     :param actual_json: \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u044b\u0439 json     :raises AssertionError: \u0435\u0441\u043b\u0438 \u0432 exp_json \u0435\u0441\u0442\u044c \u043f\u043e\u043b\u044f \u0441\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0442\u043b\u0438\u0447\u0430\u044e\u0442\u0441\u044f \u0438\u043b\u0438 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0435\u0442 \u0432 actual_json     \"\"\"     root = 'root:' if isinstance(actual_json, list) else ''     compare_res = compare_json_left_in_right(exp_json, actual_json, key=root, path=root)     assert not compare_res, BodyLogMsg(response) \\         .add_compare_result(compare_res) \\         .add_request_url() \\         .add_response_info() \\         .get_message()   def assert_response_body_fields(request, response, exp_obj=None, rmv_ids=True):     \"\"\"     \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u043e\u0442\u0432\u0435\u0442 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u044f \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u0441 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u043c     :param request: \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 request \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 pytest     :param response: \u043e\u0442\u0432\u0435\u0442 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430     :param exp_obj: \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442     :param rmv_ids: \u0444\u043b\u0430\u0433: \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 True - \u0443\u0434\u0430\u043b\u044f\u0435\u0442 id \u0438\u0437 \u0442\u0435\u043b\u0430 \u043e\u0442\u0432\u0435\u0442\u0430 \u043f\u0440\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0435, False - \u043d\u0435 \u0443\u0434\u0430\u043b\u044f\u0435\u0442     \"\"\"     exp_json = read_json_test_data(request) if exp_obj is None else exp_obj     act_json = remove_ids(response.json()) if rmv_ids else response.json()     assert_left_in_right_json(response, exp_json, act_json)   def assert_response_body_value(response, exp, act, text=None):     \"\"\"     \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u043e\u0442\u0432\u0435\u0442 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0441 \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u043c \u0434\u043b\u044f \u0442\u0435\u043b\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430     :param response: \u043e\u0442\u0432\u0435\u0442 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430     :param exp: \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435     :param act: \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435     :param text: \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u0432\u0435\u0441\u0442\u0438 \u043f\u0440\u0438 \u043d\u0435\u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u0438 exp \u0438 act     \"\"\"     assert exp == act, BodyValueLogMsg(response) \\         .add_error_info(text) \\         .add_compare_result(exp, act) \\         .add_request_url() \\         .add_response_info() \\         .get_message()   def assert_empty_list(response):     \"\"\"     \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0447\u0442\u043e \u0442\u0435\u043b\u043e \u043e\u0442\u0432\u0435\u0442\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043f\u0443\u0441\u0442\u043e\u0439 \u0441\u043f\u0438\u0441\u043e\u043a     :param response: \u043e\u0442\u0432\u0435\u0442 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430     \"\"\"     assert_left_in_right_json(response, [], response.json())   def assert_bad_request(request, response):     \"\"\"     \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0447\u0442\u043e \u0442\u0435\u043b\u043e \u043e\u0442\u0432\u0435\u0442\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 BAD REQUEST     :param request: \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 request \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 pytest     :param response: \u043e\u0442\u0432\u0435\u0442 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430     \"\"\"     assert_response_body_fields(request, response, exp_obj=read_json_common_response_data(\"bad_request_response\"))   def assert_not_found(request, response, obj_id):     \"\"\"     \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0447\u0442\u043e \u0442\u0435\u043b\u043e \u043e\u0442\u0432\u0435\u0442\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 NOT FOUND     :param request: \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 request \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 pytest     :param response: \u043e\u0442\u0432\u0435\u0442 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430     :param obj_id: id \u043e\u0431\u044a\u0435\u043a\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0435 \u043d\u0430\u0448\u0435\u043b     \"\"\"     exp = read_json_common_response_data(\"not_found_obj_response\")     exp['error'] = exp['error'].format(obj_id)     assert_response_body_fields(request, response, exp_obj=exp)   def assert_not_exist(request, response, obj_id):     \"\"\"     \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0447\u0442\u043e \u0442\u0435\u043b\u043e \u043e\u0442\u0432\u0435\u0442\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 NOT EXIST     :param request: \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 request \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 pytest     :param response: \u043e\u0442\u0432\u0435\u0442 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430     :param obj_id: id \u043e\u0431\u044a\u0435\u043a\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0435 \u043d\u0430\u0448\u0435\u043b     \"\"\"     exp = read_json_test_data(request)     exp['error'] = exp['error'].format(obj_id)     assert_response_body_fields(request, response, exp_obj=exp, rmv_ids=False) <\/code><\/pre>\n<p>\u0411\u0430\u0437\u043e\u0432\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b<code>assertion<\/code>\u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0442\u0441\u044f \u0441<code>assert<\/code>. \u041a\u043b\u0430\u0441\u0441<code>LogMsg<\/code>\u0438 \u0435\u0433\u043e \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u043d\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u0432\u044b\u0432\u043e\u0434\u0430 \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u0445 \u043b\u043e\u0433\u043e\u0432 \u0432 stdout \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0435\u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u044f \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u043e\u0433\u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u0441 \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u043c.<\/p>\n<p>\u0414\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0441\u0445\u0435\u043c\u044b \u043e\u0442\u0432\u0435\u0442\u0430 \u0443\u0434\u043e\u0431\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Pydantic. \u042d\u0442\u043e \u043c\u043d\u043e\u0433\u043e\u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u0430\u044f \u043b\u0438\u0431\u0430 \u0434\u043b\u044f \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u0434\u0435\u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 json \u0441\u043e \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u043c\u0438 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0430\u043c\u0438 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438. \u0414\u043b\u044f \u0435\u0435 \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u044e\u0442\u0441\u044f \u044d\u0442\u0430\u043b\u043e\u043d\u043d\u044b\u0435 \u043c\u043e\u0434\u0435\u043b\u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c\u044b\u0445 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432. \u0412 \u043f\u0430\u043f\u043a\u0443<code>models<\/code> \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0444\u0430\u0439\u043b<code>object_models.py<\/code>\u0441 \u043c\u043e\u0434\u0435\u043b\u044f\u043c\u0438. \u0412\u0441\u0435 \u043e\u043d\u0438 \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u044e\u0442\u0441\u044f \u043e\u0442<code>BaseModel<\/code>.<\/p>\n<pre><code class=\"python\">from typing import List  from pydantic import BaseModel, Field   class ObjectData(BaseModel):     year: int     price: float     cpu_model: str = Field(alias=\"CPU model\")     hard_disk_size: str = Field(alias=\"Hard disk size\")   class CustomObj(BaseModel):     name: str   class CustomObjData(BaseModel):     bool: bool     int: int     float: float     string: str     array: List[str]     obj: CustomObj   class ObjectOutSchema(BaseModel):     id: str     name: str     data: ObjectData   class ObjectCreateOutSchema(BaseModel):     id: str     name: str | None     data: ObjectData | None     createdAt: str   class CustomObjCreateOutSchema(BaseModel):     id: str     name: str     data: CustomObjData     createdAt: str   class ObjectUpdateOutSchema(BaseModel):     id: str     name: str | None     data: ObjectData | None     updatedAt: str   class CustomObjUpdateOutSchema(BaseModel):     id: str     name: str     data: CustomObjData     updatedAt: str <\/code><\/pre>\n<p>\u0422\u0430\u043a\u0436\u0435, \u0447\u0442\u043e\u0431\u044b \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0435 \u0442\u0435\u043b\u043e \u043e\u0442\u0432\u0435\u0442\u0430 \u0441 \u044d\u0442\u0430\u043b\u043e\u043d\u043d\u044b\u043c, \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043a\u043b\u0430\u0441\u0441\u044b-\u0443\u0442\u0438\u043b\u0438\u0442\u044b \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0444\u0430\u0439\u043b\u0430\u043c\u0438 \u0438 json.<\/p>\n<p>\u0424\u0430\u0439\u043b<code>files_utils.py<\/code><\/p>\n<pre><code class=\"python\">import json   def get_test_data_path():     return \"test_data\"   def get_common_response_path():     return f\"{get_test_data_path()}\/common\/responses\"   def get_common_requests_path():     return f\"{get_test_data_path()}\/common\/requests\"   def read_json_file_data(path):     \"\"\"     \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 json \u0444\u0430\u0439\u043b\u0430 \u0432 \u0432\u0438\u0434\u0435 dict     :param path: \u043f\u0443\u0442\u044c \u0434\u043e \u0444\u0430\u0439\u043b\u0430 \u0431\u0435\u0437 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f json     \"\"\"     with open(f\"{path}.json\", \"r\") as f:         data = json.load(f)     return data   def read_json_test_data(request):     \"\"\"     \u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0430 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 json     :param request: \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 request \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 pytest     :return: \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0430 \u0438\u0437 \u043f\u0430\u043f\u043a\u0438 test_data     \"\"\"     return read_json_file_data(f\"{get_test_data_path()}\/{request.node.originalname}\")   def read_json_common_response_data(file_name):     \"\"\"     \u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0430 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 json \u0438\u0437 \u043e\u0431\u0449\u0435\u0439 \u043f\u0430\u043f\u043a\u0438     :param file_name: \u0438\u043c\u044f \u0444\u0430\u0439\u043b\u0430 \u0431\u0435\u0437 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f json     :return: \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0430 \u0438\u0437 \u043f\u0430\u043f\u043a\u0438 test_data\/common\/responses     \"\"\"     return read_json_file_data(f\"{get_common_response_path()}\/{file_name}\")   def read_json_common_request_data(file_name):     \"\"\"     \u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0430 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 json \u0438\u0437 \u043e\u0431\u0449\u0435\u0439 \u043f\u0430\u043f\u043a\u0438     :param file_name: \u0438\u043c\u044f \u0444\u0430\u0439\u043b\u0430 \u0431\u0435\u0437 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f json     :return: \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0430 \u0438\u0437 \u043f\u0430\u043f\u043a\u0438 test_data\/common\/requests     \"\"\"     return read_json_file_data(f\"{get_common_requests_path()}\/{file_name}\") <\/code><\/pre>\n<p>\u0424\u0430\u0439\u043b<code>json_utils.py<\/code><\/p>\n<pre><code class=\"python\">def remove_ids(origin_dict):     \"\"\"     \u0443\u0434\u0430\u043b\u044f\u0435\u0442 \u043a\u043b\u044e\u0447\u0438 \u0438\u0437 \u0441\u043b\u043e\u0432\u0430\u0440\u044f, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0435\u0441\u0442\u044c id     :param origin_dict: \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u0441\u043b\u043e\u0432\u0430\u0440\u044c     :return: \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u0441 \u0432\u044b\u043f\u0438\u043b\u0435\u043d\u043d\u044b\u043c\u0438 id     \"\"\"      def rmv_ids(node):         remove_keys = []         if isinstance(node, dict):             for key, value in node.items():                 rmv_ids(value)                 if key == 'id':                     remove_keys.append(key)             for key in remove_keys:                 del node[key]         elif isinstance(node, list):             for item in node:                 rmv_ids(item)      res = origin_dict.copy()     rmv_ids(res)     return res   def compare_json_left_in_right(json1, json2, key='', path=''):     \"\"\"     \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u0442, \u0447\u0442\u043e \u0432\u0441\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043a\u043b\u044e\u0447\u0435\u0439 \u0438\u0437 json1 \u0435\u0441\u0442\u044c \u0432 json2, \u043b\u0438\u0448\u043d\u0438\u0435 \u043a\u043b\u044e\u0447\u0438 \u0438\u0437 \u043b\u0435\u0432\u043e\u0433\u043e json - \u0438\u0433\u043d\u043e\u0440\u0438\u0440\u0443\u044e\u0442\u0441\u044f     :param json1: \u044d\u0442\u0430\u043b\u043e\u043d\u043d\u044b\u0439 \u0441\u043b\u043e\u0432\u0430\u0440\u043e     :param json2: \u0441\u043b\u043e\u0432\u0430\u0440\u044c, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0438\u0434\u0435\u0442 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435     :param key: \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0435 \u0438\u043c\u044f \u043a\u043b\u044e\u0447\u0430     :param path: \u043f\u0443\u0442\u044c \u0434\u043e \u043a\u043b\u044e\u0447\u0430, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u043e \u043d\u0435\u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439     :return: \u0435\u0441\u043b\u0438 \u0432 \u043f\u0440\u0430\u0432\u043e\u043c \u0441\u043b\u043e\u0432\u0430\u0440\u0435 \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0441\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0438\u0437 \u043b\u0435\u0432\u043e\u0433\u043e \u0441\u043b\u043e\u0432\u0430\u0440\u044f, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0441\u043b\u043e\u0432\u0430\u0440\u044c     \u0444\u043e\u0440\u043c\u0430\u0442\u0430 {\"\u043a\u043b\u044e\u0447_\u0432_\u043a\u043e\u0442\u043e\u0440\u043e\u043c_\u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u043e_\u0440\u0430\u0437\u043b\u0438\u0447\u0438\u0435\": {\"expected\": value, \"actual\": value, \"path\": \u043f\u043e\u043b\u043d\u044b\u0439_\u043f\u0443\u0442\u044c_\u0434\u043e_\u043a\u043b\u044e\u0447\u0430}}     \"\"\"     diff_dict = {}     if isinstance(json1, dict) and isinstance(json2, dict):         for key in json1:             if key not in json2:                 diff_dict[key] = {\"expected\": json1[key], \"actual\": \"key undefined\", \"path\": f\"{path}{key}\"}                 continue             diff_dict.update(compare_json_left_in_right(json1[key], json2[key], key, f\"{path}{key}:\"))     elif json1 != json2:         diff_dict[key] = {\"expected\": json1, \"actual\": json2, \"path\": path[:-1]}     return diff_dict <\/code><\/pre>\n<p>\u0421 \u043c\u0435\u0442\u043e\u0434\u0430\u043c\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043b\u0438. \u041f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u0442\u0435\u0441\u0442\u043e\u0432. \u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u043e\u0432 \u043d\u0430 GET \u043c\u0435\u0442\u043e\u0434\u044b. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0448\u0430\u0431\u043b\u043e\u043d \u0441 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0430\u043c\u0438 \u0438 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u0431\u0443\u0434\u0435\u043c \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u0440\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u0447\u0435\u043a-\u043b\u0438\u0441\u0442\u043e\u0432. <\/p>\n<p>\u0415\u0441\u0442\u044c \u043e\u0431\u0449\u0438\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u043c\u0435\u0442\u043e\u0434\u0430, \u0438\u0441\u0445\u043e\u0434\u044f \u0438\u0437 \u0435\u0433\u043e \u0442\u0438\u043f\u0430 (GET, POST \u0438.\u0442.\u0434). \u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u043c\u0435\u0442\u043e\u0434\u0430 \u043d\u0430\u043c \u043d\u0430\u0434\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c 2 \u043f\u0443\u043d\u043a\u0442\u0430: \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c, \u0447\u0442\u043e \u043c\u0435\u0442\u043e\u0434 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0441\u0432\u043e\u044e \u0441\u0443\u0442\u044c \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0442\u0438\u043f\u0430 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0435\u0433\u043e \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0443. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0441\u0443\u0442\u044c \u043c\u0435\u0442\u043e\u0434\u0430 GET &#8212; \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430. \u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 GET \u043c\u0435\u0442\u043e\u0434 \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e\u043c \u0442\u0435\u0441\u0442\u043e\u0432 \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u043c\u0435\u0442\u043e\u0434 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443, \u0437\u0430\u043b\u043e\u0436\u0435\u043d\u043d\u0443\u044e \u0432 \u044d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434.<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<td>\n<p align=\"left\">\u041c\u0435\u0442\u043e\u0434<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041f\u0443\u043d\u043a\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">GET<\/p>\n<\/td>\n<td>\n<p align=\"left\">1 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0441\u0442\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u0430:<br \/>&#8212; \u0432 \u0442\u0435\u0441\u0442\u0430\u0445 \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0437\u0430\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d \u0444\u0430\u0439\u043b \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043d\u0430 \u044d\u0442\u0430\u043b\u043e\u043d\u043d\u043e\u0441\u0442\u044c \u0431\u0435\u0437 \u0430\u0439\u0434\u0438\u0448\u043d\u0438\u043a\u043e\u0432 (\u0444\u0430\u0439\u043b \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432 \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435), \u0432 \u0431\u0430\u0437\u0435 \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0437\u0430\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d \u043e\u0431\u044a\u0435\u043a\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f<br \/>&#8212; \u0434\u0435\u043b\u0430\u0435\u043c get \u0437\u0430\u043f\u0440\u043e\u0441 \u0441 \u043d\u0443\u0436\u043d\u044b\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c<br \/>&#8212; \u0434\u0435\u043b\u0430\u0435\u043c \u043f\u043e\u043b\u043d\u043e\u0435 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435 \u043e\u0442\u0432\u0435\u0442\u0430 \u0441 \u044d\u0442\u0430\u043b\u043e\u043d\u043d\u044b\u043c \u0444\u0430\u0439\u043b\u043e\u043c<\/p>\n<p align=\"left\">2 \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u0420\u0430\u0441\u043f\u0438\u0448\u0435\u043c \u0447\u0435\u043a-\u043b\u0438\u0441\u0442\u044b, \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0432 \u0438\u0445 \u043d\u0430 \u043f\u043e\u0437\u0438\u0442\u0438\u0432\u043d\u044b\u0435 \u0438 \u043d\u0435\u0433\u0430\u0442\u0438\u0432\u043d\u044b\u0435. \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0410\u041f\u0418 \u043c\u0435\u0442\u043e\u0434 GET \/objects \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c, \u0447\u0442\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0442\u0441\u044f \u043f\u0440\u0438 \u0432\u0430\u043b\u0438\u0434\u043d\u044b\u0445 \u0438 \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u044b\u0445 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u0445.<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<td>\n<p align=\"center\"><strong>\u041f\u043e\u0437\u0438\u0442\u0438\u0432\u043d\u044b\u0435<\/strong><\/p>\n<\/td>\n<td>\n<p align=\"center\"><strong>\u041d\u0435\u0433\u0430\u0442\u0438\u0432\u043d\u044b\u0435<\/strong><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"center\">\u0437\u0430\u043f\u0440\u043e\u0441 \u0441 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438 \u043f\u043e-\u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e<\/p>\n<p align=\"center\">\u0437\u0430\u043f\u0440\u043e\u0441 \u0441 1 \u0441\u0443\u0449. \u0430\u0439\u0434\u0438\u0448\u043d\u0438\u043a\u043e\u043c<\/p>\n<p align=\"center\">\u0437\u0430\u043f\u0440\u043e\u0441 \u0441 2 \u0441\u0443\u0449. \u0430\u0439\u0434\u0438\u0448\u043d\u0438\u043a\u0430\u043c\u0438<\/p>\n<\/td>\n<td>\n<p align=\"center\">\u0437\u0430\u043f\u0440\u043e\u0441 \u0441 \u043d\u0435\u0441\u0443\u0449. \u0430\u0439\u0434\u0438\u0448\u043d\u0438\u043a\u043e\u043c<\/p>\n<p align=\"center\">\u0437\u0430\u043f\u0440\u043e\u0441 \u0441 \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u044b\u043c \u0430\u0439\u0434\u0438\u0448\u043d\u0438\u043a\u043e\u043c<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<h3>\u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u043f\u0435\u0440\u0432\u044b\u0439 \u0442\u0435\u0441\u0442<\/h3>\n<p>\u0424\u0430\u0439\u043b<code>test_objects.py<\/code><\/p>\n<pre><code class=\"python\">from http import HTTPStatus  import pytest from assertions.objects_assertion import should_be_posted_success, should_be_updated_success, should_be_deleted_success, \\     should_be_valid_objects_response  from api.api_client import ApiClient from api.objects_api import get_objects, get_object, post_object, put_object, delete_object from assertions.assertion_base import assert_status_code, assert_response_body_fields, assert_bad_request, \\     assert_not_found, assert_empty_list, assert_schema, assert_not_exist from models.object_models import ObjectOutSchema, ObjectCreateOutSchema, CustomObjCreateOutSchema, \\     ObjectUpdateOutSchema, CustomObjUpdateOutSchema from utilities.files_utils import read_json_test_data, read_json_common_request_data   class TestObjects:     \"\"\"     \u0422\u0435\u0441\u0442\u044b \/objects     \"\"\"      @pytest.fixture(scope='class')     def client(self):         return ApiClient()      def test_get_objects(self, client, request):         \"\"\"         \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0437\u0430\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0438\u0437 \u0431\u0430\u0437\u044b \u0441 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438 \u043f\u043e-\u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e,         GET \/objects         \"\"\"         # \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0438\u0437 \u0431\u0430\u0437\u044b         response = get_objects(client)          # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u0432 \u043e\u0442\u0432\u0435\u0442 \u043f\u0440\u0438\u0448\u043b\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u043e\u0436\u0438\u0434\u0430\u0435\u043c         assert_status_code(response, HTTPStatus.OK)         assert_response_body_fields(request, response)<\/code><\/pre>\n<p>\u0412 \u0442\u0435\u0441\u0442\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435: \u043c\u044b \u0434\u0435\u043b\u0430\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u0447\u0442\u043e \u043a\u043e\u0434 \u043e\u0442\u0432\u0435\u0442\u0430 200, \u0430 \u0437\u0430\u0442\u0435\u043c \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u0432 \u043e\u0442\u0432\u0435\u0442\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u043e\u043c\u0443 (\u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0442\u0435\u043b\u0430 \u043e\u0442\u0432\u0435\u0442\u0430), \u0434\u0435\u043b\u0430\u044f \u043f\u0440\u044f\u043c\u043e\u0435 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435 \u0441 \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u0447\u043d\u044b\u043c \u0444\u0430\u0439\u043b\u043e\u043c. \u041f\u0440\u0438 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0438, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u043d\u0430\u0440\u0443\u0448\u0430\u0442\u044c 4 \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0435 \u043a \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u044e\u0449\u0435\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 (\u0433\u0438\u0431\u043a\u043e\u0441\u0442\u044c), \u0432\u044b\u043f\u0438\u043b\u0438\u0432\u0430\u0435\u043c \u0432\u0441\u0435 id \u0438\u0437 \u043e\u0442\u0432\u0435\u0442\u0430. id &#8212; \u044d\u0442\u043e \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u0430. \u0412\u044b\u043f\u0438\u043b\u0438\u0432\u0430\u0435\u043c \u043c\u044b \u0438\u0445, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438 \u043a\u0430\u043a\u043e\u043c-\u043b\u0438\u0431\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0411\u0414 \u043d\u0430\u0448\u0438 \u0442\u0435\u0441\u0442\u044b \u043d\u0435 \u043f\u043e\u0441\u044b\u043f\u0430\u043b\u0438\u0441\u044c, \u0435\u0441\u043b\u0438 \u043b\u043e\u0433\u0438\u043a\u0430 \u043c\u0435\u0442\u043e\u0434\u0430 \u0438 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043f\u0440\u0438 \u0442\u0430\u043a\u043e\u043c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0438 \u043d\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u0438\u0441\u044c. \u0412 \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u0447\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435 \u0438\u0445 \u0442\u0430\u043a\u0436\u0435 \u043d\u0435\u0442. \u041f\u0440\u043e\u0432\u0435\u0440\u043e\u0447\u043d\u044b\u0439 \u0444\u0430\u0439\u043b \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<p>\u0424\u0430\u0439\u043b<code>test_get_objects.json<\/code><\/p>\n<pre><code class=\"python\">[  {    \"name\": \"Google Pixel 6 Pro\",    \"data\": {      \"color\": \"Cloudy White\",      \"capacity\": \"128 GB\"    }  },  {    \"name\": \"Apple iPhone 12 Mini, 256GB, Blue\",    \"data\": null  },  {    \"name\": \"Apple iPhone 12 Pro Max\",    \"data\": {      \"color\": \"Cloudy White\",      \"capacity GB\": 512    }  },  {    \"name\": \"Apple iPhone 11, 64GB\",    \"data\": {      \"price\": 389.99,      \"color\": \"Purple\"    }  },  {    \"name\": \"Samsung Galaxy Z Fold2\",    \"data\": {      \"price\": 689.99,      \"color\": \"Brown\"    }  },  {    \"name\": \"Apple AirPods\",    \"data\": {      \"generation\": \"3rd\",      \"price\": 120    }  },  {    \"name\": \"Apple MacBook Pro 16\",    \"data\": {      \"year\": 2019,      \"price\": 1849.99,      \"CPU model\": \"Intel Core i9\",      \"Hard disk size\": \"1 TB\"    }  },  {    \"name\": \"Apple Watch Series 8\",    \"data\": {      \"Strap Colour\": \"Elderberry\",      \"Case Size\": \"41mm\"    }  },  {    \"name\": \"Beats Studio3 Wireless\",    \"data\": {      \"Color\": \"Red\",      \"Description\": \"High-performance wireless noise cancelling headphones\"    }  },  {    \"name\": \"Apple iPad Mini 5th Gen\",    \"data\": {      \"Capacity\": \"64 GB\",      \"Screen size\": 7.9    }  },  {    \"name\": \"Apple iPad Mini 5th Gen\",    \"data\": {      \"Capacity\": \"254 GB\",      \"Screen size\": 7.9    }  },  {    \"name\": \"Apple iPad Air\",    \"data\": {      \"Generation\": \"4th\",      \"Price\": \"419.99\",      \"Capacity\": \"64 GB\"    }  },  {    \"name\": \"Apple iPad Air\",    \"data\": {      \"Generation\": \"4th\",      \"Price\": \"519.99\",      \"Capacity\": \"256 GB\"    }  } ]<\/code><\/pre>\n<p>\u041f\u043e \u0438\u0442\u043e\u0433\u0443 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043f\u0440\u0438\u043e\u0431\u0440\u0435\u0442\u0430\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0432\u0438\u0434:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/4cd\/6d3\/c84\/4cd6d3c84ed00f078e4b7ed9bd615e2a.png\" width=\"310\" height=\"545\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/4cd\/6d3\/c84\/4cd6d3c84ed00f078e4b7ed9bd615e2a.png\"\/><\/figure>\n<p>\u0420\u0430\u0441\u0448\u0438\u0440\u0438\u043c \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0435 \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u0430 GET \/objects \u043f\u043e \u043d\u0430\u0448\u0438\u043c \u0447\u0435\u043a-\u043b\u0438\u0441\u0442\u0430\u043c. \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043a\u0435\u0439\u0441\u044b \u201c\u0437\u0430\u043f\u0440\u043e\u0441 \u0441 2 \u0441\u0443\u0449. \u0430\u0439\u0434\u0438\u0448\u043d\u0438\u043a\u0430\u043c\u0438\u201d \u0438 \u201c\u0437\u0430\u043f\u0440\u043e\u0441 \u0441 1 \u0441\u0443\u0449. \u0430\u0439\u0434\u0438\u0448\u043d\u0438\u043a\u0430\u043c\u0438\u201d \u0442\u0440\u0435\u0431\u0443\u044e\u0442 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043a\u043b\u0430\u0441\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0442\u0430\u043a\u0438\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438<code>objects_assertion.py<\/code>. \u041c\u0435\u0442\u043e\u0434\u044b \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0442\u0441\u044f \u0441 \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u0430<code>should_be<\/code>.<\/p>\n<p>\u0424\u0430\u0439\u043b<code>objects_assertion.py<\/code><\/p>\n<pre><code class=\"python\">from http import HTTPStatus  from api.objects_api import get_object from assertions.assertion_base import assert_response_body_fields, assert_status_code, assert_response_body_value from utilities.files_utils import read_json_test_data   def should_be_valid_objects_response(request, response, param):     # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u0432 \u043e\u0442\u0432\u0435\u0442\u0435 \u0441\u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u044b \u043e\u0436\u0438\u0434\u0430\u0435\u043c     exp = read_json_test_data(request)[param['index']]     exp_len, act_len = len(exp), len(response.json())     assert_response_body_value(response, exp_len, act_len,                                text=\"\u041e\u0416\u0418\u0414\u0410\u0415\u041c\u041e\u0415 \u041a\u041e\u041b\u0418\u0427\u0415\u0421\u0422\u0412\u041e \u041e\u0411\u042a\u0415\u041a\u0422\u041e\u0412 \u041d\u0415 \u0421\u041e\u0412\u041f\u0410\u041b\u041e \u0421 \u0424\u0410\u041a\u0422\u0418\u0427\u0415\u0421\u041a\u0418\u041c\")      # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f \u0432 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0441\u0442\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u043f\u043e\u043b\u0435\u0439 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432     assert_response_body_fields(request, response, exp)<\/code><\/pre>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0442\u0435\u0441\u0442\u044b \u0432 \u0444\u0430\u0439\u043b<code>test_objects.py<\/code><\/p>\n<pre><code class=\"python\">from http import HTTPStatus  import pytest from assertions.objects_assertion import should_be_posted_success, should_be_updated_success, should_be_deleted_success, \\     should_be_valid_objects_response  from api.api_client import ApiClient from api.objects_api import get_objects, get_object, post_object, put_object, delete_object from assertions.assertion_base import assert_status_code, assert_response_body_fields, assert_bad_request, \\     assert_not_found, assert_empty_list, assert_schema, assert_not_exist from models.object_models import ObjectOutSchema, ObjectCreateOutSchema, CustomObjCreateOutSchema, \\     ObjectUpdateOutSchema, CustomObjUpdateOutSchema from utilities.files_utils import read_json_test_data, read_json_common_request_data   class TestObjects:     \"\"\"     \u0422\u0435\u0441\u0442\u044b \/objects     \"\"\"      @pytest.fixture(scope='class')     def client(self):         return ApiClient()      def test_get_objects(self, client, request):         \"\"\"         \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0437\u0430\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0438\u0437 \u0431\u0430\u0437\u044b \u0441 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438 \u043f\u043e-\u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e,         GET \/objects         \"\"\"         # \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0438\u0437 \u0431\u0430\u0437\u044b         response = get_objects(client)          # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u0432 \u043e\u0442\u0432\u0435\u0442 \u043f\u0440\u0438\u0448\u043b\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u043e\u0436\u0438\u0434\u0430\u0435\u043c         assert_status_code(response, HTTPStatus.OK)         assert_response_body_fields(request, response)      @pytest.mark.parametrize(\"param\", [{\"index\": 0, \"ids\": [1]}, {\"index\": 1, \"ids\": [1, 2]}])     def test_get_objects_id_param(self, client, request, param):         \"\"\"         \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0437\u0430\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0438\u0437 \u0431\u0430\u0437\u044b \u0441 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c ids,         GET \/objects         \"\"\"         # \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043c\u0430\u0441\u0441\u0438\u0432 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0441 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u043c\u0438 \u0430\u0439\u0434\u0438\u0448\u043d\u0438\u043a\u0430\u043c\u0438         response = get_objects(client, *param['ids'])          # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u0432 \u043e\u0442\u0432\u0435\u0442 \u043f\u0440\u0438\u0448\u043b\u0438 \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b, id \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043c\u044b \u0437\u0430\u043f\u0440\u043e\u0441\u0438\u043b\u0438         assert_status_code(response, HTTPStatus.OK)         should_be_valid_objects_response(request, response, param)      def test_get_objects_not_exist_id(self, client):         \"\"\"         \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u0437 \u0431\u0430\u0437\u044b \u043e\u0431\u044a\u0435\u043a\u0442 \u0441 \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c id,         GET \/objects         \"\"\"         # \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442, \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0435         response = get_objects(client, 8523697415)          # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u0432 \u043e\u0442\u0432\u0435\u0442 \u043f\u0440\u0438\u0448\u0435\u043b \u043f\u0443\u0441\u0442\u043e\u0439 \u0441\u043f\u0438\u0441\u043e\u043a         assert_status_code(response, HTTPStatus.OK)         assert_empty_list(response)      def test_get_objects_invalid_id(self, client):         \"\"\"         \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u0437 \u0431\u0430\u0437\u044b \u043e\u0431\u044a\u0435\u043a\u0442 \u0441 \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u044b\u043c \u043f\u043e \u0442\u0438\u043f\u0443 id,         GET \/objects         \"\"\"         # \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442, \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0432 \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u044b\u0439 \u043f\u043e \u0442\u0438\u043f\u0443 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 ids         response = get_objects(client, \"kjdsf23321\")          # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u0432 \u043e\u0442\u0432\u0435\u0442 \u043f\u0440\u0438\u0448\u0435\u043b \u043f\u0443\u0441\u0442\u043e\u0439 \u0441\u043f\u0438\u0441\u043e\u043a         assert_status_code(response, HTTPStatus.OK)         assert_empty_list(response)<\/code><\/pre>\n<p>\u041f\u043e \u0438\u0442\u043e\u0433\u0443 \u043c\u044b 5 \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043b\u0438, \u0447\u0442\u043e \u043c\u0435\u0442\u043e\u0434 GET \/objects \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0438\u0437 \u0431\u0430\u0437\u044b \u043f\u0440\u0438 \u0440\u0430\u0437\u043d\u044b\u0445 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u0445 \u0438 \u0432\u044b\u0434\u0430\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u0440\u0438 \u043d\u0435\u0432\u0435\u0440\u043d\u044b\u0445 id.<\/p>\n<p>\u0420\u0430\u0441\u043f\u0438\u0448\u0435\u043c \u043f\u043e \u0442\u0430\u043a\u043e\u043c\u0443 \u0436\u0435 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0443 \u0447\u0435\u043a-\u043b\u0438\u0441\u0442 \u0434\u043b\u044f \u043c\u0435\u0442\u043e\u0434\u0430 GET \/objects\/{id}<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<td>\n<p align=\"center\"><strong>\u041f\u043e\u0437\u0438\u0442\u0438\u0432\u043d\u044b\u0435<\/strong><\/p>\n<\/td>\n<td>\n<p align=\"center\"><strong>\u041d\u0435\u0433\u0430\u0442\u0438\u0432\u043d\u044b\u0435<\/strong><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"center\">\u0437\u0430\u043f\u0440\u043e\u0441 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430<\/p>\n<\/td>\n<td>\n<p align=\"center\">\u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u0412 \u0444\u0430\u0439\u043b<code>test_objects.py<\/code>\u0434\u043e\u0431\u0430\u0432\u0438\u043c<\/p>\n<pre><code class=\"python\">def test_get_object(self, client, request):     \"\"\"     \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0437\u0430\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0438\u0437 \u0431\u0430\u0437\u044b,     GET \/objects\/{id}     \"\"\"     # \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0435\u0434\u0438\u043d\u0438\u0447\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430     response = get_object(client, 7)      # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0435\u043d \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u043e\u0442 \u043e\u0431\u044a\u0435\u043a\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0437\u0430\u043f\u0440\u043e\u0441\u0438\u043b\u0438     assert_status_code(response, HTTPStatus.OK)     assert_schema(response, ObjectOutSchema)     assert_response_body_fields(request, response)  def test_get_object_not_exist(self, client, request):     \"\"\"     \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u0437 \u0431\u0430\u0437\u044b \u0435\u0434\u0438\u043d\u0438\u0447\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u0441 \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c id,     GET \/objects\/{id}     \"\"\"     # \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u043c \u0435\u0434\u0438\u043d\u0438\u0447\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0441 \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c id     response = get_object(client, 1593576458)      # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u0441\u0435\u0440\u0432\u0435\u0440 \u0432\u0435\u0440\u043d\u0443\u043b NOT FOUND \u043e\u0442\u0432\u0435\u0442     assert_status_code(response, HTTPStatus.NOT_FOUND)     assert_not_exist(request, response, 1593576458)<\/code><\/pre>\n<p>\u041a\u0430\u043a \u0432\u0438\u0434\u043d\u043e \u0432 \u0442\u0435\u0441\u0442\u0435<code>test_get_object<\/code>\u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0430\u0441\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0441\u0445\u0435\u043c\u044b \u043e\u0442\u0432\u0435\u0442\u0430 (\u043c\u0435\u0442\u043e\u0434<code>assert_schema<\/code>). Pydantic \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442, \u0447\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043f\u043e\u043b\u044f \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442, \u0447\u0442\u043e \u043e\u043d\u0438 \u0441\u0442\u0440\u043e\u0433\u043e \u0442\u043e\u0433\u043e \u0442\u0438\u043f\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u043e\u0436\u0438\u0434\u0430\u0435\u043c. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0448\u0438\u0431\u043a\u0438, \u043e\u043d \u0432\u044b\u0432\u0435\u0434\u0435\u0442 \u043d\u0430\u043c \u043f\u043e\u043b\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0442 \u0441\u0445\u0435\u043c\u0435 \u043f\u043e \u0442\u0438\u043f\u0443 \u0438\u043b\u0438 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u044b.<\/p>\n<p>\u041f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a \u043c\u0435\u0442\u043e\u0434\u0443 POST.\u00a0<\/p>\n<p>C\u0443\u0442\u044c \u043c\u0435\u0442\u043e\u0434\u0430 POST &#8212; \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435. \u041a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u044d\u0442\u043e \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u043f\u043e\u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044e \u043d\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430. \u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e\u043c \u0442\u0435\u0441\u0442\u043e\u0432 \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u043c\u0435\u0442\u043e\u0434 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435, \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443, \u0437\u0430\u043b\u043e\u0436\u0435\u043d\u043d\u0443\u044e \u0432 \u044d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434.<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<td>\n<p align=\"left\">\u041c\u0435\u0442\u043e\u0434<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041f\u0443\u043d\u043a\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">POST<\/p>\n<\/td>\n<td>\n<p align=\"left\">1 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0441\u0442\u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435:<br \/>&#8212; \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442<br \/>&#8212; \u0437\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u0435\u043c \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442<br \/>&#8212; \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442<br \/>&#8212; \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u043e\u0431\u044a\u0435\u043a\u0442 \u0432 \u043e\u0442\u0432\u0435\u0442\u0435 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u0435\u043d<br \/>&#8212; \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u0432 \u0431\u0430\u0437\u0435 \u044d\u0442\u043e\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d<\/p>\n<p align=\"left\">2 \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0410\u041f\u0418 \u043c\u0435\u0442\u043e\u0434 POST \/objects \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442, \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0432\u0441\u0435\u0433\u0434\u0430 \u0435\u0441\u0442\u044c 2 \u043f\u043e\u043b\u044f <code>name<\/code><strong> <\/strong>\u0438<strong> <\/strong><code>data<\/code><strong>. <\/strong>\u0421\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432\u0441\u0435\u0433\u0434\u0430 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432 \u044d\u0442\u0438 2 \u043f\u043e\u043b\u044f, \u0435\u0441\u043b\u0438 \u043e\u043d\u0438 \u043d\u0435 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u044b, \u0441\u0435\u0440\u0432\u0435\u0440 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442 \u0438\u0445 \u0432 null. \u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043d\u0430\u0448\u0430 \u0437\u0430\u0434\u0430\u0447\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c, \u0447\u0442\u043e \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u044d\u0442\u0438 \u043f\u043e\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044e\u0442\u0441\u044f \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0438 \u0441 \u0437\u0430\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u043e\u0439, \u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 \u0431\u0430\u0437\u0443 \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442. \u0420\u0430\u0441\u043f\u0438\u0448\u0435\u043c \u0447\u0435\u043a-\u043b\u0438\u0441\u0442.<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<td>\n<p align=\"center\"><strong>\u041f\u043e\u0437\u0438\u0442\u0438\u0432\u043d\u044b\u0435<\/strong><\/p>\n<\/td>\n<td>\n<p align=\"center\"><strong>\u041d\u0435\u0433\u0430\u0442\u0438\u0432\u043d\u044b\u0435<\/strong><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"center\">\u0437\u0430\u043f\u0438\u0441\u044c \u043f\u0443\u0441\u0442\u043e\u0433\u043e \u0442\u0435\u043b\u0430 \u0432 \u0431\u0430\u0437\u0443<\/p>\n<p align=\"center\">\u0437\u0430\u043f\u0438\u0441\u044c name \u0438 data \u0441 \u043f\u043e\u043b\u044f\u043c\u0438 \u0432\u0441\u0435\u0445 \u0442\u0438\u043f\u043e\u0432 \u0432 \u0431\u0430\u0437\u0443<\/p>\n<\/td>\n<td>\n<p align=\"center\">\u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u043e\u0433\u043e json<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u0412 \u0444\u0430\u0439\u043b <code>test_objects.py<\/code> \u0434\u043e\u0431\u0430\u0432\u0438\u043c<\/p>\n<pre><code class=\"python\">def test_post_object_empty_body(self, client, request):     \"\"\"     \u0437\u0430\u043f\u0438\u0441\u044c \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0432 \u0431\u0430\u0437\u0443 \u0441 \u043f\u0443\u0441\u0442\u044b\u043c \u0442\u0435\u043b\u043e\u043c,     POST \/objects     \"\"\"     # \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u0432 \u0431\u0430\u0437\u0443 \u0441 \u043f\u0443\u0441\u0442\u044b\u043c \u0442\u0435\u043b\u043e\u043c     response = post_object(client, json={})      # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u043e\u0431\u044a\u0435\u043a\u0442 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0437\u0430\u043f\u0438\u0441\u0430\u043d \u0432 \u0431\u0430\u0437\u0443     assert_status_code(response, HTTPStatus.OK)     assert_schema(response, ObjectCreateOutSchema)     should_be_posted_success(request, client, response, exp_obj={\"data\": None, \"name\": None})  def test_post_object_with_full_body(self, client, request):     \"\"\"     \u0437\u0430\u043f\u0438\u0441\u044c \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0432 \u0431\u0430\u0437\u0443 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u043c \u0442\u0435\u043b\u043e\u043c,     POST \/objects     \"\"\"     # \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u0432 \u0431\u0430\u0437\u0443 \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u043c\u0438 \u043f\u043e\u043b\u044f\u043c\u0438     exp_obj = read_json_common_request_data(\"valid_post_object\")     response = post_object(client, json=exp_obj)      # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u043e\u0431\u044a\u0435\u043a\u0442 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0437\u0430\u043f\u0438\u0441\u0430\u043d \u0432 \u0431\u0430\u0437\u0443     assert_status_code(response, HTTPStatus.OK)     assert_schema(response, CustomObjCreateOutSchema)     should_be_posted_success(request, client, response, exp_obj)  def test_post_object_send_invalid_json(self, client, request):     \"\"\"     \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0432 \u0431\u0430\u0437\u0443 \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u044b\u0439 json,     POST \/objects     \"\"\"     # \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0437\u0430\u043f\u0438\u0441\u044c \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0432 \u0431\u0430\u0437\u0443 \u0441 \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u044b\u043c json \u0432 \u0442\u0435\u043b\u0435     response = post_object(client, content='{\"name\",}', headers={\"Content-Type\": \"application\/json\"})      # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u0441\u0435\u0440\u0432\u0435\u0440 \u0434\u0430\u043b BAD REQUEST \u043e\u0442\u0432\u0435\u0442     assert_status_code(response, HTTPStatus.BAD_REQUEST)     assert_bad_request(request, response)<\/code><\/pre>\n<p>\u041f\u043e \u0438\u0442\u043e\u0433\u0443 3 \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u043c\u044b \u0443\u0431\u0435\u0434\u0438\u043b\u0438\u0441\u044c, \u0447\u0442\u043e POST \/objects \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u0432\u0430\u043b\u0438\u0434\u043d\u044b\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0432 \u0431\u0430\u0437\u0443, \u043f\u043e\u0440\u043e\u0436\u0434\u0430\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0441 \u043f\u0443\u0441\u0442\u044b\u043c\u0438 \u043f\u043e\u043b\u044f\u043c\u0438 <code>name<\/code> \u0438 <code>data<\/code>\u0438, \u0435\u0441\u043b\u0438 \u043c\u044b \u0438\u0445 \u043d\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u043b\u0438, \u043d\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u044b\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b.<\/p>\n<p>\u041f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a \u043c\u0435\u0442\u043e\u0434\u0443 PUT. C\u0443\u0442\u044c \u043c\u0435\u0442\u043e\u0434\u0430 PUT &#8212; \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435. \u041a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e \u044d\u0442\u043e \u043f\u043e\u043b\u043d\u043e\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u0430. \u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u043c\u0435\u0442\u043e\u0434 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435, \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443.<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<td>\n<p align=\"left\">\u041c\u0435\u0442\u043e\u0434<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041f\u0443\u043d\u043a\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">PUT<\/p>\n<\/td>\n<td>\n<p align=\"left\">1 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0441\u0442\u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0432 \u0431\u0430\u0437\u0435:<br \/>&#8212; \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c id \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430<br \/>&#8212; \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u0441 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c\u0438<br \/>&#8212; \u0437\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u0435\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0434\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0435\u0433\u043e \u0432 \u0431\u0430\u0437\u0435<br \/>&#8212; \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u0432 \u0431\u0430\u0437\u0435 \u043e\u0431\u044a\u0435\u043a\u0442<br \/>&#8212; \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u043e\u0431\u044a\u0435\u043a\u0442 \u0432 \u043e\u0442\u0432\u0435\u0442\u0435 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d<br \/>&#8212; \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u0432 \u0431\u0430\u0437\u0435 \u044d\u0442\u043e\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d<\/p>\n<p align=\"left\">2 \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0410\u041f\u0418 \u043c\u0435\u0442\u043e\u0434 PUT \/objects\/{id} \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442 2 \u043f\u043e\u043b\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u0430: <code>name<\/code> \u0438 <code>data<\/code><strong>. <\/strong>\u041f\u0440\u0438 \u0437\u0430\u043f\u0438\u0441\u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0432 \u0431\u0430\u0437\u0443<strong> <\/strong>\u043b\u043e\u0433\u0438\u043a\u0430 \u0442\u0430\u043a\u0430\u044f \u0436\u0435 \u043a\u0430\u043a \u0443 \u043c\u0435\u0442\u043e\u0434\u0430 POST. \u0420\u0430\u0441\u043f\u0438\u0448\u0435\u043c \u0447\u0435\u043a-\u043b\u0438\u0441\u0442.<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<td>\n<p align=\"center\"><strong>\u041f\u043e\u0437\u0438\u0442\u0438\u0432\u043d\u044b\u0435<\/strong><\/p>\n<\/td>\n<td>\n<p align=\"center\"><strong>\u041d\u0435\u0433\u0430\u0442\u0438\u0432\u043d\u044b\u0435<\/strong><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"center\">\u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 name \u0438 data \u0441 \u043f\u043e\u043b\u044f\u043c\u0438 \u0432\u0441\u0435\u0445 \u0442\u0438\u043f\u043e\u0432<\/p>\n<p align=\"center\">\u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0430 \u043f\u0443\u0441\u0442\u043e\u0439<\/p>\n<\/td>\n<td>\n<p align=\"center\">\u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0435\u0441\u0443\u0449. \u043e\u0431\u044a\u0435\u043a\u0442\u0430<\/p>\n<p align=\"center\">\u043d\u0430 \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u0412 \u0444\u0430\u0439\u043b <code>test_objects.py<\/code> \u0434\u043e\u0431\u0430\u0432\u0438\u043c<\/p>\n<pre><code class=\"python\">def test_put_object_with_empty_body(self, client, request):     \"\"\"     \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0432 \u0431\u0430\u0437\u0435 \u043d\u0430 \u043f\u0443\u0441\u0442\u043e\u0439 \u043e\u0431\u044a\u0435\u043a\u0442,     PUT \/objects\/{id}     \"\"\"     # \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u0432 \u0431\u0430\u0437\u0443 \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u043c\u0438 \u043f\u043e\u043b\u044f\u043c\u0438     post_obj = read_json_common_request_data(\"valid_post_object\")     response = post_object(client, json=post_obj)     assert_status_code(response, HTTPStatus.OK)      # \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u044d\u0442\u043e\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 \u043d\u0430 \u043f\u0443\u0441\u0442\u043e\u0439 \u043e\u0431\u044a\u0435\u043a\u0442     exp_json = {\"id\": response.json()['id'], \"name\": None, \"data\": None}     response = put_object(client, exp_json['id'], json={})      # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u043e\u0431\u044a\u0435\u043a\u0442 \u0431\u044b\u043b \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d     assert_status_code(response, HTTPStatus.OK)     assert_schema(response, ObjectUpdateOutSchema)     should_be_updated_success(request, client, response, exp_json)  def test_put_object_with_full_body(self, client, request):     \"\"\"     \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0432\u0441\u0435\u0445 \u043f\u043e\u043b\u0435\u0439 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0432 \u0431\u0430\u0437\u0435,     PUT \/objects\/{id}     \"\"\"     # \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u0432 \u0431\u0430\u0437\u0443 \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u043c\u0438 \u043f\u043e\u043b\u044f\u043c\u0438     post_obj = read_json_common_request_data(\"valid_post_object\")     response = post_object(client, json=post_obj)     assert_status_code(response, HTTPStatus.OK)      # \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u043f\u043e\u043b\u0435\u0439 \u044d\u0442\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043d\u0430 \u043d\u043e\u0432\u044b\u0435     put_obj = read_json_test_data(request)     put_obj_id = response.json()['id']     response = put_object(client, put_obj_id, json=put_obj)      # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u043e\u0431\u044a\u0435\u043a\u0442 \u0431\u044b\u043b \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d     assert_status_code(response, HTTPStatus.OK)     assert_schema(response, CustomObjUpdateOutSchema)     put_obj['id'] = put_obj_id     should_be_updated_success(request, client, response, put_obj)  def test_put_object_send_invalid_json(self, client, request):     \"\"\"     \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442, \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0432 \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u044b\u0439 json,     PUT \/objects\/{id}     \"\"\"     # \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u0432 \u0431\u0430\u0437\u0443 \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u043c\u0438 \u043f\u043e\u043b\u044f\u043c\u0438     response = post_object(client, json=read_json_common_request_data(\"valid_post_object\"))     assert_status_code(response, HTTPStatus.OK)      # \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u044d\u0442\u043e\u0442 \u043e\u0431\u044a\u0435\u043a\u0442, \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0432 \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u044b\u0439 json     response = put_object(client, response.json()['id'], content='{\"name\",}',                           headers={\"Content-Type\": \"application\/json\"})      # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u0441\u0435\u0440\u0432\u0435\u0440 \u0434\u0430\u043b BAD REQUEST \u043e\u0442\u0432\u0435\u0442     assert_status_code(response, HTTPStatus.BAD_REQUEST)     assert_bad_request(request, response)  def test_put_object_update_non_exist_obj(self, client, request):     \"\"\"     \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u043e\u0431\u044a\u0435\u043a\u0442,     PUT \/objects\/{id}     \"\"\"     # \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442     obj_id = \"ff8081818a194cb8018a79e7545545ac\"     response = put_object(client, obj_id, json={})      # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u0441\u0435\u0440\u0432\u0435\u0440 \u0434\u0430\u043b NOT FOUND \u043e\u0442\u0432\u0435\u0442     assert_status_code(response, HTTPStatus.NOT_FOUND)     assert_not_found(request, response, obj_id)<\/code><\/pre>\n<p>\u041f\u043e \u0438\u0442\u043e\u0433\u0443 4 \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u043c\u044b \u0443\u0431\u0435\u0434\u0438\u043b\u0438\u0441\u044c, \u0447\u0442\u043e PUT \/objects\/{id} \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442 \u0432\u0441\u0435 \u043f\u043e\u043b\u044f \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430, id \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u044b \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u043b\u0438, \u0438 \u043d\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043d\u0430 \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u043e\u0435.<\/p>\n<p>C\u0443\u0442\u044c \u043c\u0435\u0442\u043e\u0434\u0430 DELETE &#8212; \u0443\u0434\u0430\u043b\u044f\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430.<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<td>\n<p align=\"left\">\u041c\u0435\u0442\u043e\u0434<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041f\u0443\u043d\u043a\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">DELETE<\/p>\n<\/td>\n<td>\n<p align=\"left\">1 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430:<br \/>&#8212; \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c id \u0443\u0434\u0430\u043b\u044f\u0435\u043c\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430<br \/>&#8212; \u0443\u0434\u0430\u043b\u044f\u0435\u043c \u0435\u0433\u043e<br \/>&#8212; \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u043e\u043d \u0443\u0434\u0430\u043b\u0435\u043d (404 \u043e\u0448\u0438\u0431\u043a\u0430)<\/p>\n<p>2 \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u0420\u0430\u0441\u043f\u0438\u0448\u0435\u043c \u0447\u0435\u043a-\u043b\u0438\u0441\u0442<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<td>\n<p align=\"center\"><strong>\u041f\u043e\u0437\u0438\u0442\u0438\u0432\u043d\u044b\u0435<\/strong><\/p>\n<\/td>\n<td>\n<p align=\"center\"><strong>\u041d\u0435\u0433\u0430\u0442\u0438\u0432\u043d\u044b\u0435<\/strong><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"center\">\u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430<\/p>\n<\/td>\n<td>\n<p align=\"center\">\u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u0412 \u0444\u0430\u0439\u043b<code>test_objects.py<\/code>\u0434\u043e\u0431\u0430\u0432\u0438\u043c<\/p>\n<pre><code class=\"python\">def test_delete_exist_object(self, client, request):     \"\"\"     \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0443\u044e\u0449\u0435\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430,     DELETE \/objects\/{id}     \"\"\"     # \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u0432 \u0431\u0430\u0437\u0443 \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u043c\u0438 \u043f\u043e\u043b\u044f\u043c\u0438     response = post_object(client, json=read_json_common_request_data(\"valid_post_object\"))     assert_status_code(response, HTTPStatus.OK)      # \u0443\u0434\u0430\u043b\u044f\u0435\u043c \u044d\u0442\u043e\u0442 \u043e\u0431\u044a\u0435\u043a\u0442     obj_id = response.json()['id']     response = delete_object(client, obj_id)      # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u043e\u0431\u044a\u0435\u043a\u0442 \u0443\u0434\u0430\u043b\u0435\u043d     assert_status_code(response, HTTPStatus.OK)     should_be_deleted_success(request, response, obj_id)  def test_delete_not_exist_object(self, client, request):     \"\"\"     \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0443\u044e\u0449\u0435\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430,     DELETE \/objects\/{id}     \"\"\"     # \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u043e\u0431\u044a\u0435\u043a\u0442     obj_id = \"ff8081818a194cb8018a79e7545545ac\"     response = delete_object(client, obj_id)      # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u0441\u0435\u0440\u0432\u0435\u0440 \u0434\u0430\u043b NOT FOUND \u043e\u0442\u0432\u0435\u0442     assert_status_code(response, HTTPStatus.NOT_FOUND)     assert_not_exist(request, response, obj_id)<\/code><\/pre>\n<p>\u041d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u0448\u0430\u0433\u0435 \u0432 \u043f\u0430\u043f\u043a\u0443<code>test_data<\/code>\u0442\u0430\u043a\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0444\u0430\u0439\u043b\u044b \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430. \u041f\u043e \u0438\u0442\u043e\u0433\u0443 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c 16 \u0442\u0435\u0441\u0442\u043e\u0432. \u0424\u0430\u0439\u043b \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c.<\/p>\n<pre><code class=\"python\">from http import HTTPStatus  import pytest  from api.api_client import ApiClient from api.objects_api import get_objects, get_object, post_object, put_object, delete_object from assertions.assertion_base import assert_status_code, assert_response_body_fields, assert_bad_request, \\     assert_not_found, assert_empty_list, assert_schema, assert_not_exist from assertions.objects_assertion import should_be_posted_success, should_be_updated_success, should_be_deleted_success, \\     should_be_valid_objects_response from models.object_models import ObjectOutSchema, ObjectCreateOutSchema, CustomObjCreateOutSchema, \\     ObjectUpdateOutSchema, CustomObjUpdateOutSchema from utilities.files_utils import read_json_test_data, read_json_common_request_data   class TestObjects:     \"\"\"     \u0422\u0435\u0441\u0442\u044b \/objects     \"\"\"      @pytest.fixture(scope='class')     def client(self):         return ApiClient()      def test_get_objects(self, client, request):         \"\"\"         \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0437\u0430\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0438\u0437 \u0431\u0430\u0437\u044b \u0441 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438 \u043f\u043e-\u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e,         GET \/objects         \"\"\"         # \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0438\u0437 \u0431\u0430\u0437\u044b         response = get_objects(client)          # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u0432 \u043e\u0442\u0432\u0435\u0442 \u043f\u0440\u0438\u0448\u043b\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u043e\u0436\u0438\u0434\u0430\u0435\u043c         assert_status_code(response, HTTPStatus.OK)         assert_response_body_fields(request, response)      @pytest.mark.parametrize(\"param\", [{\"index\": 0, \"ids\": [1]}, {\"index\": 1, \"ids\": [1, 2]}])     def test_get_objects_id_param(self, client, request, param):         \"\"\"         \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0437\u0430\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0438\u0437 \u0431\u0430\u0437\u044b \u0441 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c ids,         GET \/objects         \"\"\"         # \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043c\u0430\u0441\u0441\u0438\u0432 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0441 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u043c\u0438 \u0430\u0439\u0434\u0438\u0448\u043d\u0438\u043a\u0430\u043c\u0438         response = get_objects(client, *param['ids'])          # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u0432 \u043e\u0442\u0432\u0435\u0442 \u043f\u0440\u0438\u0448\u043b\u0438 \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b, id \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043c\u044b \u0437\u0430\u043f\u0440\u043e\u0441\u0438\u043b\u0438         assert_status_code(response, HTTPStatus.OK)         should_be_valid_objects_response(request, response, param)      def test_get_objects_not_exist_id(self, client):         \"\"\"         \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u0437 \u0431\u0430\u0437\u044b \u043e\u0431\u044a\u0435\u043a\u0442 \u0441 \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c id,         GET \/objects         \"\"\"         # \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442, \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0435         response = get_objects(client, 8523697415)          # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u0432 \u043e\u0442\u0432\u0435\u0442 \u043f\u0440\u0438\u0448\u0435\u043b \u043f\u0443\u0441\u0442\u043e\u0439 \u0441\u043f\u0438\u0441\u043e\u043a         assert_status_code(response, HTTPStatus.OK)         assert_empty_list(response)      def test_get_objects_invalid_id(self, client):         \"\"\"         \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u0437 \u0431\u0430\u0437\u044b \u043e\u0431\u044a\u0435\u043a\u0442 \u0441 \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u044b\u043c \u043f\u043e \u0442\u0438\u043f\u0443 id,         GET \/objects         \"\"\"         # \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442, \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0432 \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u044b\u0439 \u043f\u043e \u0442\u0438\u043f\u0443 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 ids         response = get_objects(client, \"kjdsf23321\")          # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u0432 \u043e\u0442\u0432\u0435\u0442 \u043f\u0440\u0438\u0448\u0435\u043b \u043f\u0443\u0441\u0442\u043e\u0439 \u0441\u043f\u0438\u0441\u043e\u043a         assert_status_code(response, HTTPStatus.OK)         assert_empty_list(response)      def test_get_object(self, client, request):         \"\"\"         \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0437\u0430\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0438\u0437 \u0431\u0430\u0437\u044b,         GET \/objects\/{id}         \"\"\"         # \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0435\u0434\u0438\u043d\u0438\u0447\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430         response = get_object(client, 7)          # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0435\u043d \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u043e\u0442 \u043e\u0431\u044a\u0435\u043a\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0437\u0430\u043f\u0440\u043e\u0441\u0438\u043b\u0438         assert_status_code(response, HTTPStatus.OK)         assert_schema(response, ObjectOutSchema)         assert_response_body_fields(request, response)      def test_get_object_not_exist(self, client, request):         \"\"\"         \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u0437 \u0431\u0430\u0437\u044b \u0435\u0434\u0438\u043d\u0438\u0447\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u0441 \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c id,         GET \/objects\/{id}         \"\"\"         # \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u043c \u0435\u0434\u0438\u043d\u0438\u0447\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0441 \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c id         response = get_object(client, 1593576458)          # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u0441\u0435\u0440\u0432\u0435\u0440 \u0432\u0435\u0440\u043d\u0443\u043b NOT FOUND \u043e\u0442\u0432\u0435\u0442         assert_status_code(response, HTTPStatus.NOT_FOUND)         assert_not_exist(request, response, 1593576458)      def test_post_object_empty_body(self, client, request):         \"\"\"         \u0437\u0430\u043f\u0438\u0441\u044c \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0432 \u0431\u0430\u0437\u0443 \u0441 \u043f\u0443\u0441\u0442\u044b\u043c \u0442\u0435\u043b\u043e\u043c,         POST \/objects         \"\"\"         # \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u0432 \u0431\u0430\u0437\u0443 \u0441 \u043f\u0443\u0441\u0442\u044b\u043c \u0442\u0435\u043b\u043e\u043c         response = post_object(client, json={})          # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u043e\u0431\u044a\u0435\u043a\u0442 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0437\u0430\u043f\u0438\u0441\u0430\u043d \u0432 \u0431\u0430\u0437\u0443         assert_status_code(response, HTTPStatus.OK)         assert_schema(response, ObjectCreateOutSchema)         should_be_posted_success(request, client, response, exp_obj={\"data\": None, \"name\": None})      def test_post_object_with_full_body(self, client, request):         \"\"\"         \u0437\u0430\u043f\u0438\u0441\u044c \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0432 \u0431\u0430\u0437\u0443 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u043c \u0442\u0435\u043b\u043e\u043c,         POST \/objects         \"\"\"         # \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u0432 \u0431\u0430\u0437\u0443 \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u043c\u0438 \u043f\u043e\u043b\u044f\u043c\u0438         exp_obj = read_json_common_request_data(\"valid_post_object\")         response = post_object(client, json=exp_obj)          # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u043e\u0431\u044a\u0435\u043a\u0442 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0437\u0430\u043f\u0438\u0441\u0430\u043d \u0432 \u0431\u0430\u0437\u0443         assert_status_code(response, HTTPStatus.OK)         assert_schema(response, CustomObjCreateOutSchema)         should_be_posted_success(request, client, response, exp_obj)      def test_post_object_send_invalid_json(self, client, request):         \"\"\"         \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0432 \u0431\u0430\u0437\u0443 \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u044b\u0439 json,         POST \/objects         \"\"\"         # \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0437\u0430\u043f\u0438\u0441\u044c \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0432 \u0431\u0430\u0437\u0443 \u0441 \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u044b\u043c json \u0432 \u0442\u0435\u043b\u0435         response = post_object(client, content='{\"name\",}', headers={\"Content-Type\": \"application\/json\"})          # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u0441\u0435\u0440\u0432\u0435\u0440 \u0434\u0430\u043b BAD REQUEST \u043e\u0442\u0432\u0435\u0442         assert_status_code(response, HTTPStatus.BAD_REQUEST)         assert_bad_request(request, response)      def test_put_object_with_empty_body(self, client, request):         \"\"\"         \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0432 \u0431\u0430\u0437\u0435 \u043d\u0430 \u043f\u0443\u0441\u0442\u043e\u0439 \u043e\u0431\u044a\u0435\u043a\u0442,         PUT \/objects\/{id}         \"\"\"         # \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u0432 \u0431\u0430\u0437\u0443 \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u043c\u0438 \u043f\u043e\u043b\u044f\u043c\u0438         post_obj = read_json_common_request_data(\"valid_post_object\")         response = post_object(client, json=post_obj)         assert_status_code(response, HTTPStatus.OK)          # \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u044d\u0442\u043e\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 \u043d\u0430 \u043f\u0443\u0441\u0442\u043e\u0439 \u043e\u0431\u044a\u0435\u043a\u0442         exp_json = {\"id\": response.json()['id'], \"name\": None, \"data\": None}         response = put_object(client, exp_json['id'], json={})          # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u043e\u0431\u044a\u0435\u043a\u0442 \u0431\u044b\u043b \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d         assert_status_code(response, HTTPStatus.OK)         assert_schema(response, ObjectUpdateOutSchema)         should_be_updated_success(request, client, response, exp_json)      def test_put_object_with_full_body(self, client, request):         \"\"\"         \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0432\u0441\u0435\u0445 \u043f\u043e\u043b\u0435\u0439 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0432 \u0431\u0430\u0437\u0435,         PUT \/objects\/{id}         \"\"\"         # \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u0432 \u0431\u0430\u0437\u0443 \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u043c\u0438 \u043f\u043e\u043b\u044f\u043c\u0438         post_obj = read_json_common_request_data(\"valid_post_object\")         response = post_object(client, json=post_obj)         assert_status_code(response, HTTPStatus.OK)          # \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u043f\u043e\u043b\u0435\u0439 \u044d\u0442\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043d\u0430 \u043d\u043e\u0432\u044b\u0435         put_obj = read_json_test_data(request)         put_obj_id = response.json()['id']         response = put_object(client, put_obj_id, json=put_obj)          # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u043e\u0431\u044a\u0435\u043a\u0442 \u0431\u044b\u043b \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d         assert_status_code(response, HTTPStatus.OK)         assert_schema(response, CustomObjUpdateOutSchema)         put_obj['id'] = put_obj_id         should_be_updated_success(request, client, response, put_obj)      def test_put_object_send_invalid_json(self, client, request):         \"\"\"         \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442, \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0432 \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u044b\u0439 json,         PUT \/objects\/{id}         \"\"\"         # \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u0432 \u0431\u0430\u0437\u0443 \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u043c\u0438 \u043f\u043e\u043b\u044f\u043c\u0438         response = post_object(client, json=read_json_common_request_data(\"valid_post_object\"))         assert_status_code(response, HTTPStatus.OK)          # \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u044d\u0442\u043e\u0442 \u043e\u0431\u044a\u0435\u043a\u0442, \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0432 \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u044b\u0439 json         response = put_object(client, response.json()['id'], content='{\"name\",}',                               headers={\"Content-Type\": \"application\/json\"})          # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u0441\u0435\u0440\u0432\u0435\u0440 \u0434\u0430\u043b BAD REQUEST \u043e\u0442\u0432\u0435\u0442         assert_status_code(response, HTTPStatus.BAD_REQUEST)         assert_bad_request(request, response)      def test_put_object_update_non_exist_obj(self, client, request):         \"\"\"         \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u043e\u0431\u044a\u0435\u043a\u0442,         PUT \/objects\/{id}         \"\"\"         # \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442         obj_id = \"ff8081818a194cb8018a79e7545545ac\"         response = put_object(client, obj_id, json={})          # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u0441\u0435\u0440\u0432\u0435\u0440 \u0434\u0430\u043b NOT FOUND \u043e\u0442\u0432\u0435\u0442         assert_status_code(response, HTTPStatus.NOT_FOUND)         assert_not_found(request, response, obj_id)      def test_delete_exist_object(self, client, request):         \"\"\"         \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0443\u044e\u0449\u0435\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430,         DELETE \/objects\/{id}         \"\"\"         # \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u0432 \u0431\u0430\u0437\u0443 \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u043c\u0438 \u043f\u043e\u043b\u044f\u043c\u0438         response = post_object(client, json=read_json_common_request_data(\"valid_post_object\"))         assert_status_code(response, HTTPStatus.OK)          # \u0443\u0434\u0430\u043b\u044f\u0435\u043c \u044d\u0442\u043e\u0442 \u043e\u0431\u044a\u0435\u043a\u0442         obj_id = response.json()['id']         response = delete_object(client, obj_id)          # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u043e\u0431\u044a\u0435\u043a\u0442 \u0443\u0434\u0430\u043b\u0435\u043d         assert_status_code(response, HTTPStatus.OK)         should_be_deleted_success(request, response, obj_id)      def test_delete_not_exist_object(self, client, request):         \"\"\"         \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0443\u044e\u0449\u0435\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430,         DELETE \/objects\/{id}         \"\"\"         # \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u043e\u0431\u044a\u0435\u043a\u0442         obj_id = \"ff8081818a194cb8018a79e7545545ac\"         response = delete_object(client, obj_id)          # \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u0441\u0435\u0440\u0432\u0435\u0440 \u0434\u0430\u043b NOT FOUND \u043e\u0442\u0432\u0435\u0442         assert_status_code(response, HTTPStatus.NOT_FOUND)         assert_not_exist(request, response, obj_id) <\/code><\/pre>\n<p>\u041f\u043e\u0434\u0432\u043e\u0434\u044f \u0438\u0442\u043e\u0433: 16 \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u043c\u044b \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u043b\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u0440\u0430\u0431\u043e\u0442\u044b 5 \u0410\u041f\u0418 \u043c\u0435\u0442\u043e\u0434\u043e\u0432. \u041a\u0430\u0436\u0434\u044b\u0439 \u0442\u0435\u0441\u0442 \u0441\u043e\u0431\u043b\u044e\u0434\u0430\u0435\u0442 4 \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f. \u0422\u0435\u0441\u0442\u044b \u0430\u0442\u043e\u043c\u0430\u0440\u043d\u044b \u0438 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b, \u0430 \u0437\u043d\u0430\u0447\u0438\u0442 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0431\u0435\u0437 \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c 1 \u0442\u0435\u0441\u0442, \u043d\u0435 \u043d\u0430\u0440\u0443\u0448\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0443 \u0434\u0440\u0443\u0433\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430. \u0422\u0435\u0441\u0442\u044b \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0433\u0438\u0431\u043a\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u0447\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b \u043c\u043e\u0436\u043d\u043e \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0445 \u0438\u043b\u0438 \u0441\u0445\u043e\u0436\u0438\u0445 \u043e\u0442\u0432\u0435\u0442\u0430\u0445, \u043a\u0430\u043a \u0432 \u043c\u0435\u0442\u043e\u0434\u0435<code>assert_bad_request<\/code>, \u0434\u0435\u043b\u0430\u044f \u043e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u044f \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0442\u0435\u0441\u0442\u043e\u0432 \u043a 1 \u0444\u0430\u0439\u043b\u0443. \u0422\u043e\u0433\u0434\u0430 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043e\u0442\u0432\u0435\u0442\u0430 \u043d\u0430 bad request \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c \u043d\u0430\u043c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u043e\u043f\u0440\u0430\u0432\u0438\u0442\u044c 1 \u0444\u0430\u0439\u043b, \u043d\u0435 \u043c\u0435\u043d\u044f\u044f \u043a\u043e\u0434 \u0441\u0430\u043c\u0438\u0445 \u0442\u0435\u0441\u0442\u043e\u0432.<\/p>\n<p>\u042d\u0442\u043e \u043c\u043e\u044f \u043f\u0435\u0440\u0432\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f. \u0421\u0442\u0430\u0440\u0430\u043b\u0441\u044f \u043a\u0430\u043a \u043c\u043e\u0433). \u041d\u0430\u0434\u0435\u044e\u0441\u044c \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0432\u0430\u043c \u0432 \u0432\u0430\u0448\u0435\u0439 \u0440\u0430\u0431\u043e\u0442\u0435, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043d\u0430\u0434\u0435\u044e\u0441\u044c, \u0447\u0442\u043e \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043d\u043e\u0432\u0438\u0447\u043a\u0430\u043c \u0432 \u043e\u0441\u0432\u043e\u0435\u043d\u0438\u0438 \u0410\u041f\u0418 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. \u0416\u0434\u0443 \u0432\u0430\u0448\u0438\u0445 \u043e\u0442\u0437\u044b\u0432\u043e\u0432 \u0438 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u0432, \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043f\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u043e\u043c\u0443 \u043f\u043e\u0434\u0445\u043e\u0434\u0443.<\/p>\n<p>\u0421\u0430\u043c \u043f\u0440\u043e\u0435\u043a\u0442 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0441\u043a\u0430\u0447\u0430\u0442\u044c \u0438\u0437 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f <a href=\"https:\/\/github.com\/HardTester\/API_testing\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/github.com\/HardTester\/API_testing<\/u><\/a>. \u041f\u043e\u0441\u043b\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0432 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0435 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u0432 \u043f\u0430\u043f\u043a\u0443 API_testing, \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c<code>requirements.txt<\/code>\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0442\u0435\u0441\u0442\u044b \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439<code>pytest<\/code>\u0438\u0437 \u043a\u043e\u0440\u043d\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/765512\/\"> https:\/\/habr.com\/ru\/articles\/765512\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><\/figure>\n<p>\u041c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u0410\u043b\u0435\u043a\u0441\u0435\u0439. \u042f \u044f\u0432\u043b\u044f\u044e\u0441\u044c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0441\u0442\u043e\u043c \u043f\u043e \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. \u041f\u0438\u0448\u0443 \u043a\u0430\u043a UI \u0442\u0435\u0441\u0442\u044b \u043d\u0430 \u0441\u0435\u043b\u0435\u043d\u0438\u0443\u043c\u0435, \u0442\u0430\u043a \u0438 \u043f\u043e\u043a\u0440\u044b\u0432\u0430\u044e \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0435 REST API.\u00a0 \u0414\u0430\u043d\u043d\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u043e\u043c \u0438 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0435\u0437\u043d\u0430 \u043a\u0430\u043a \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0449\u0438\u043c, \u0442\u0430\u043a \u0438 \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0449\u0438\u043a\u0430\u043c \u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0442\u043e\u0440\u0430\u043c. \u041d\u043e \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u043b\u0435\u0437\u043d\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c \u0438 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0441\u0442\u0430\u043c \u0438\u0437 \u0441\u043c\u0435\u0436\u043d\u044b\u0445 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0439. \u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u043f\u043e\u0448\u0430\u0433\u043e\u0432\u043e \u043f\u043e\u043a\u0440\u043e\u0435\u043c \u0442\u0435\u0441\u0442\u0430\u043c\u0438 REST API\u00a0 <a href=\"https:\/\/restful-api.dev\/\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/restful-api.dev<\/u><\/a> \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 GET, POST, PUT, DELETE. \u041f\u043e\u0434\u0445\u043e\u0434, \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u0432 \u0441\u0442\u0430\u0442\u044c\u0435, \u044f \u0441\u0430\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e \u043d\u0430 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435.<\/p>\n<h3>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0441\u0442\u0430\u0442\u044c\u0438<\/h3>\n<ol>\n<li>\n<p><strong>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438<\/strong><\/p>\n<\/li>\n<li>\n<p><strong>\u041d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432:<br \/><\/strong><\/p>\n<ol>\n<li>\n<p>\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u00a0\u0441\u0438\u0441\u0442\u0435\u043c\u0435 \u0442\u0435\u0441\u0442\u043e\u0432<\/p>\n<\/li>\n<li>\n<p>\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/p>\n<\/li>\n<li>\n<p>\u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0410\u041f\u0418 \u043a\u043b\u0438\u0435\u043d\u0442\u0430<\/p>\n<\/li>\n<li>\n<p>\u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430<\/p>\n<\/li>\n<li>\n<p>\u043a\u043e\u0434 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430<\/p>\n<\/li>\n<li>\n<p>\u0442\u0435\u0441\u0442\u044b \u043d\u0430 GET, POST, PUT, DELETE<\/p>\n<\/li>\n<\/ol>\n<\/li>\n<li>\n<p><strong>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/strong><\/p>\n<\/li>\n<\/ol>\n<h3>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438<\/h3>\n<ol>\n<li>\n<p><code>python 3.11.4<\/code><\/p>\n<\/li>\n<li>\n<p><code>pytest 7.4.0<\/code> &#8212; \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435:<a href=\"https:\/\/pytest-docs-ru.readthedocs.io\/ru\/latest\/usage.html\" rel=\"noopener noreferrer nofollow\"> <\/a><a href=\"https:\/\/pytest-docs-ru.readthedocs.io\/ru\/latest\/getting-started.html\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/pytest-docs-ru.readthedocs.io\/ru\/latest\/getting-started.html<\/u><\/a><\/p>\n<\/li>\n<li>\n<p><code>pydantic 2.3.0<\/code> &#8212; \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u043e\u0442\u0432\u0435\u0442\u0430. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435:<a href=\"https:\/\/docs.pydantic.dev\/\" rel=\"noopener noreferrer nofollow\"> <u>https:\/\/docs.pydantic.dev\/<\/u><\/a><\/p>\n<\/li>\n<li>\n<p><code>httpx 0.24.1<\/code> &#8212; \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435:<a href=\"https:\/\/www.python-httpx.org\/quickstart\/\" rel=\"noopener noreferrer nofollow\"> <u>https:\/\/www.python-httpx.org\/quickstart\/<\/u><\/a><\/p>\n<\/li>\n<li>\n<p>\u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0435 \u0410\u041f\u0418 &#8212; <a href=\"https:\/\/restful-api.dev\/\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/restful-api.dev<\/u><\/a><\/p>\n<\/li>\n<li>\n<p>\u0441\u0440\u0435\u0434\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 &#8212; <code>PyCharm<\/code>.<\/p>\n<\/li>\n<\/ol>\n<h3>\u041d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432<\/h3>\n<p>\u041f\u0435\u0440\u0435\u0434 \u0442\u0435\u043c, \u043a\u0430\u043a \u0447\u0442\u043e-\u0442\u043e \u043f\u0438\u0441\u0430\u0442\u044c, \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u043d\u0430\u0431\u043e\u0440 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0441\u043e\u0431\u043b\u044e\u0434\u0430\u0442\u044c \u0432 \u043d\u0430\u0448\u0435\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 \u0442\u0435\u0441\u0442\u043e\u0432, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e:<\/p>\n<ol>\n<li>\n<p>\u0438\u0434\u0435\u0439\u043d\u043e\u0441\u0442\u044c (\u043a\u0430\u0436\u0434\u044b\u0439 \u0442\u0435\u0441\u0442 \u0438\u043c\u0435\u0435\u0442 \u0447\u0435\u0442\u043a\u0443\u044e \u0438\u0434\u0435\u044e)<\/p>\n<\/li>\n<li>\n<p>\u0430\u0442\u043e\u043c\u0430\u0440\u043d\u043e\u0441\u0442\u044c \u0438\u0434\u0435\u0438 (\u0432 \u0442\u0435\u0441\u0442\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0430 \u0438\u0434\u0435\u044f)<\/p>\n<\/li>\n<li>\n<p>\u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u043e\u0442 \u0434\u0440\u0443\u0433\u0438\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 (\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0432 \u043e\u0434\u043d\u043e\u043c \u0442\u0435\u0441\u0442\u0435 \u043d\u0435 \u0432\u043b\u0438\u044f\u044e\u0442 \u043d\u0430 \u0434\u0440\u0443\u0433\u043e\u0439, \u0442\u0435\u0441\u0442\u044b \u043c\u043e\u0433\u0443\u0442 \u0438\u0434\u0442\u0438 \u0432 \u043b\u044e\u0431\u043e\u043c \u043f\u043e\u0440\u044f\u0434\u043a\u0435)<\/p>\n<\/li>\n<li>\n<p>\u0433\u0438\u0431\u043a\u043e\u0441\u0442\u044c \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 (\u0442\u0435\u0441\u0442\u044b \u043c\u043e\u0436\u043d\u043e \u043b\u0435\u0433\u043a\u043e \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438 \u043d\u0430 \u0434\u0440\u0443\u0433\u0443\u044e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0442\u0435\u043d\u0434 \u0438\u043b\u0438 \u0431\u044b\u0441\u0442\u0440\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0432 \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438)<\/p>\n<\/li>\n<\/ol>\n<p>\u0421\u043e\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u0435 \u044d\u0442\u0438\u0445 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043d\u0430\u043c \u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043d\u043e \u0438 \u043c\u0438\u043d\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043b\u0438\u0448\u043d\u0438\u0439 \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433.<\/p>\n<h3>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h3>\n<p>\u0421\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u043a\u0430\u0440\u043a\u0430\u0441 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0441 \u043f\u0430\u043f\u043a\u0430\u043c\u0438, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u043c\u0438:<\/p>\n<ul>\n<li>\n<p><strong>api<\/strong> &#8212; \u043a\u043b\u0430\u0441\u0441\u044b \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 api<\/p>\n<\/li>\n<li>\n<p><strong>logs<\/strong> &#8212; \u043b\u043e\u0433\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443<\/p>\n<\/li>\n<li>\n<p><strong>assertions<\/strong> &#8212; \u043a\u043b\u0430\u0441\u0441\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432<\/p>\n<\/li>\n<li>\n<p><strong>models<\/strong> &#8212; \u043c\u043e\u0434\u0435\u043b\u0438 pydantic \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0441\u0445\u0435\u043c \u043e\u0442\u0432\u0435\u0442\u0430<\/p>\n<\/li>\n<li>\n<p><strong>test_data<\/strong> &#8212; \u044d\u0442\u0430\u043b\u043e\u043d\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b json \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043e\u0442\u0432\u0435\u0442\u043e\u0432<\/p>\n<\/li>\n<li>\n<p><strong>tests<\/strong> &#8212; \u043a\u043b\u0430\u0441\u0441\u044b \u0441 \u0442\u0435\u0441\u0442\u0430\u043c\u0438<\/p>\n<\/li>\n<li>\n<p><strong>utilities<\/strong> &#8212; \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043a\u043b\u0430\u0441\u0441\u044b-\u0443\u0442\u0438\u043b\u0438\u0442\u044b (\u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 json \u0438.\u0442.\u0434)<\/p>\n<\/li>\n<\/ul>\n<p>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<figure class=\"\"><\/figure>\n<p>\u041f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0442\u0430\u043a\u0436\u0435 \u0431\u044b\u043b\u0430 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u0430 \u043f\u0438\u0442\u043e\u043d\u043e\u0432\u0441\u043a\u0430\u044f \u043f\u0430\u043f\u043a\u0430<code>venv<\/code> (\u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 <a href=\"https:\/\/docs.python.org\/3\/library\/venv.html\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/docs.python.org\/3\/library\/venv.html<\/u><\/a>) \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a. \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u043a\u043e\u0440\u0435\u043d\u044c \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0444\u0430\u0439\u043b<code>requirements.txt<\/code><strong> <\/strong>\u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043e\u0439:<\/p>\n<pre><code class=\"python\">httpx==0.24.1 pytest==7.4.0 pydantic==2.3.0 python-dotenv==1.0.0<\/code><\/pre>\n<p>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 <code>pip install -r requirements.txt<\/code><\/p>\n<h3>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0410\u041f\u0418 \u043a\u043b\u0438\u0435\u043d\u0442\u0430<\/h3>\n<p>\u0412 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 httpx. \u0418\u0437 \u0444\u0438\u0447\u0435\u0439 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0441\u0435\u0441\u0441\u0438\u0438 (<a href=\"https:\/\/en.wikipedia.org\/wiki\/HTTP_persistent_connection\" rel=\"noopener noreferrer nofollow\"><u>HTTP connection pooling<\/u><\/a>) \u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b. \u041e\u0447\u0435\u043d\u044c \u043f\u043e\u043b\u0435\u0437\u043d\u0430 \u0432 \u043e\u0441\u0432\u043e\u0435\u043d\u0438\u0438. httpx \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043a\u043b\u0430\u0441\u0441 Client. \u041e\u043d \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u0442\u043a\u0440\u044b\u0442\u044c TCP \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0443\u0433\u043e\u0434\u043d\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u043d\u0435\u0433\u043e \u043e\u0434\u043d\u043e\u0433\u043e. \u042d\u0442\u043e \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0442 \u0432\u0440\u0435\u043c\u044f \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443.\u00a0<\/p>\n<p>\u041d\u0430\u0448 \u0410\u041f\u0418 \u043a\u043b\u0438\u0435\u043d\u0442 \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043f\u043e \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0443: \u0442\u0438\u043f \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u043f\u0443\u0442\u044c \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0433\u043e \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u0430.<\/p>\n<p>\u0412 \u043f\u0430\u043f\u043a\u0443<code>api<\/code>\u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0444\u0430\u0439\u043b<code>api_client.py<\/code><\/p>\n<pre><code class=\"python\">import os  from httpx import Client, Response  from utilities.logger_utils import logger   class ApiClient(Client):     \"\"\"     \u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0433\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0430 httpx.     \"\"\"      def __init__(self):         super().__init__(base_url=f\"https:\/\/{os.getenv('RESOURSE_URL')}\")      def request(self, method, url, **kwargs) -> Response:         \"\"\"         \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u043b\u043e\u0433\u0438\u043a\u0438 \u043c\u0435\u0442\u043e\u0434\u0430 httpx request \u0441 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u043c \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0442\u0438\u043f\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438 \u0435\u0433\u043e url,         \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u043b\u0438 \u043d\u0435\u0442 \u0437\u0430\u0434\u0430\u0435\u0442\u0441\u044f \u0432 \u0444\u0430\u0439\u043b\u0435 .env         :param method: \u043c\u0435\u0442\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c (POST, GET \u0438.\u0442.\u0434)         :param url: \u043f\u0443\u0442\u044c \u043d\u0430 \u0434\u043e\u043c\u0435\u043d\u0435, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441         \"\"\"          if eval(os.getenv(\"USE_LOGS\")):             logger.info(f'{method} {url}')         return super().request(method, url, **kwargs)<\/code><\/pre>\n<p>\u041d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u0432 \u0444\u0430\u0439\u043b<code>objects_api.py<\/code><\/p>\n<pre><code class=\"python\">from api import routes   def get_objects(client, *ids):     return client.get(routes.Routes.OBJECTS, params={'id': ids} if ids else None)   def get_object(client, obj_id):     return client.get(routes.Routes.OBJECTS_ITEM.format(obj_id))   def post_object(client, **kwargs):     return client.post(routes.Routes.OBJECTS, **kwargs)   def put_object(client, obj_id, **kwargs):     return client.put(routes.Routes.OBJECTS_ITEM.format(obj_id), **kwargs)   def delete_object(client, obj_id):     return client.delete(routes.Routes.OBJECTS_ITEM.format(obj_id)) <\/code><\/pre>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043a\u043b\u0430\u0441\u0441 \u0441 \u043f\u0443\u0442\u044f\u043c\u0438 \u0432\u043d\u0443\u0442\u0440\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0432 \u0444\u0430\u0439\u043b<code>routes.py<\/code><\/p>\n<pre><code class=\"python\">from enum import Enum   class Routes(str, Enum):     OBJECTS = '\/objects'     OBJECTS_ITEM = '\/objects\/{}'      def __str__(self) -> str:         return self.value<\/code><\/pre>\n<p>\u041f\u0435\u0440\u0435\u0434 \u0442\u0435\u043c, \u043a\u0430\u043a \u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0435\u0440\u0432\u044b\u0439 \u0442\u0435\u0441\u0442, \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u043a\u043e\u0440\u0435\u043d\u044c \u043f\u0440\u043e\u0435\u043a\u0442\u0430<code>conftest.py<\/code>, <code>.env<\/code> \u0444\u0430\u0439\u043b \u0438<code>pytest.ini<\/code>. \u041e\u043d\u0438 \u043d\u0443\u0436\u043d\u044b \u0434\u043b\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432 \u043d\u0430\u0448\u0435\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u0435.<\/p>\n<p>\u0424\u0430\u0439\u043b<code>conftest.py<\/code><\/p>\n<pre><code class=\"python\">import logging import os  from dotenv import load_dotenv  from utilities.logger_utils import logger   def pytest_configure(config):     # \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u043d\u0430 \u043a\u043e\u0440\u0435\u043d\u044c \u043f\u0440\u043e\u0435\u043a\u0442\u0430 (\u044d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043f\u0440\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u0443\u0442\u0438 \u043a \u0444\u0430\u0439\u043b\u0430\u043c)     os.chdir(os.path.dirname(os.path.abspath(__file__)))      # \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435-\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 \/.env     load_dotenv(dotenv_path=\".env\")      # \u0437\u0430\u0434\u0430\u0435\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043b\u043e\u0433\u0433\u0435\u0440\u0430     path = \"logs\/\"     os.makedirs(os.path.dirname(path), exist_ok=True)     file_handler = logging.FileHandler(path + \"\/info.log\", \"w\")     file_handler.setLevel(logging.INFO)     file_handler.setFormatter(logging.Formatter(\"%(lineno)d: %(asctime)s %(message)s\"))      # \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0439 \u043b\u043e\u0433\u0433\u0435\u0440     custom_logger = logging.getLogger(\"custom_loger\")     custom_logger.setLevel(logging.INFO)     custom_logger.addHandler(file_handler)   def pytest_runtest_setup(item):     logger.info(f\"{item.name}:\")<\/code><\/pre>\n<p>\u0424\u0430\u0439\u043b<code>.env<\/code><\/p>\n<pre><code class=\"python\">RESOURSE_URL=api.restful-api.dev USE_LOGS=True<\/code><\/pre>\n<p>\u0424\u0430\u0439\u043b<code>pytest.ini<\/code><\/p>\n<pre><code class=\"python\">[pytest] addopts =    --rootdir=.    -p no:logging<\/code><\/pre>\n<p>\u0412\u0441\u0435 \u0433\u043e\u0442\u043e\u0432\u043e \u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430. \u041f\u043e \u0438\u0442\u043e\u0433\u0443 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<figure class=\"\"><\/figure>\n<h3>\u041d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430<\/h3>\n<p>\u0421\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043a \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u043d\u0430\u0448\u0438\u0445 \u0442\u0435\u0441\u0442\u043e\u0432. \u041a\u0430\u0436\u0434\u044b\u0439 \u0442\u0435\u0441\u0442 \u0438\u043c\u0435\u0435\u0442 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0438 \u043d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b (\u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u043b\u043e\u0433\u0438\u043a\u0438 \u0441\u0430\u043c\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430). \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043d\u043e \u044d\u0442\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/p>\n<ol>\n<li>\n<p>\u041e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043a\u043e\u0434\u0430 \u043e\u0442\u0432\u0435\u0442\u0430 (\u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0439 \u0438 \u043f\u0440\u0438\u0448\u0435\u0434\u0448\u0438\u0439 \u043a\u043e\u0434).<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0441\u0445\u0435\u043c\u044b \u043e\u0442\u0432\u0435\u0442\u0430 (\u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0442\u0435\u043b\u0430 \u043e\u0442\u0432\u0435\u0442\u0430 \u0438 \u0442\u0438\u043f\u044b \u043f\u043e\u043b\u0435\u0439).<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0442\u0435\u043b\u0430 \u043e\u0442\u0432\u0435\u0442\u0430 \u0438 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438<\/p>\n<\/li>\n<\/ol>\n<p>1 \u0438 2\u00a0 \u043f\u0443\u043d\u043a\u0442\u044b \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0442.\u043a \u043b\u044e\u0431\u043e\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u0434\u0430\u0435\u0442 \u043d\u0430\u043c \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0439 \u043a\u043e\u0434 \u043e\u0442\u0432\u0435\u0442\u0430. \u0422\u0440\u0435\u0442\u0438\u0439 \u043f\u0443\u043d\u043a\u0442 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c, \u0435\u0441\u043b\u0438 \u0443 \u043e\u0442\u0432\u0435\u0442\u0430 \u0435\u0441\u0442\u044c \u0442\u0435\u043b\u043e (json). 4 \u043f\u0443\u043d\u043a\u0442 \u043f\u043e\u0434\u0440\u0430\u0437\u0443\u043c\u0435\u0432\u0430\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0441\u0442\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u043f\u043e\u043b\u0435\u0439 \u0432 \u0442\u0435\u043b\u0435 \u043e\u0442\u0432\u0435\u0442\u0430, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0438\u0434\u0435\u0438 \u043d\u0430\u0448\u0435\u0433\u043e \u0442\u0435\u0441\u0442\u0430. \u042d\u0442\u043e\u0442 \u043f\u0443\u043d\u043a\u0442 \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c, \u0435\u0441\u043b\u0438 \u0443 \u043e\u0442\u0432\u0435\u0442\u0430 \u0435\u0441\u0442\u044c \u0442\u0435\u043b\u043e.<\/p>\n<p>\u0414\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a 2, 3 \u0438 4 \u043f\u0443\u043d\u043a\u0442\u043e\u0432 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b assertion. \u0412 \u043f\u0430\u043f\u043a\u0443<code>assertions<\/code> \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043a\u043b\u0430\u0441\u0441<code>assertion_base.py<\/code><\/p>\n<pre><code class=\"python\">from typing import Type  from pydantic import BaseModel  from utilities.files_utils import read_json_test_data, read_json_common_response_data from utilities.json_utils import compare_json_left_in_right, remove_ids   class LogMsg:     \"\"\"     \u0411\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0435 \u043b\u043e\u0433\u043e\u0432 AssertionError. \u041a\u043e\u043d\u0441\u0442\u0440\u0443\u0438\u0440\u0443\u0435\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0432 \u0441\u0432\u043e\u0435 \u043f\u043e\u043b\u0435 _msg.     \"\"\"      def __init__(self, where, response):         self._msg = \"\"         self._response = response         self._where = where      def add_request_url(self):         \"\"\"         \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0431 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u043c \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u0437\u0430\u043f\u0440\u043e\u0441\u0435         \"\"\"         self._msg += f\"\u0421\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 (url, query params, \u0442\u0435\u043b\u043e):\\n\" \\                      f\"\\tURL: {self._response.request.url}\\n\"         self._msg += f\"\\tmethod: {self._response.request.method}\\n\"         self._msg += f\"\\theaders: {dict(self._response.request.headers)}\\n\"         if hasattr(self._response.request, 'params') and self._response.request.params:             self._msg += f\"\\tquery params: {self._response.request.params}\\n\"         else:             self._msg += f\"\\tquery params:\\n\"         if hasattr(self._response.request, 'content') and self._response.request.read():             self._msg += f\"\\tbody: {self._response.request.read()}\\n\"         else:             self._msg += f\"\\tbody:\\n\"         return self      def add_response_info(self):         \"\"\"         \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u043c \u0442\u0435\u043b\u0430 \u043e\u0442\u0432\u0435\u0442\u0430         \"\"\"         self._msg += f\"\u0422\u0435\u043b\u043e \u043e\u0442\u0432\u0435\u0442\u0430:\\n\\t{self._response.content}\\n\"         return self      def add_error_info(self, text):         if text:             self._msg += f\"\\n{text}\\n\"         else:             self._msg += \"\\n\"         return self      def get_message(self):         return self._msg   class BodyLogMsg(LogMsg):     \"\"\"     \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0432 \u043b\u043e\u0433\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a \u0442\u0435\u043b\u0430 \u043e\u0442\u0432\u0435\u0442\u0430.     \"\"\"      def __init__(self, response):         super().__init__('\u0412 \u0422\u0415\u041b\u0415 \u041e\u0422\u0412\u0415\u0422\u0410', response)      def add_compare_result(self, diff):         \"\"\"         \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0433\u043e json \u0441 \u044d\u0442\u0430\u043b\u043e\u043d\u043e\u043c         :param diff: \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043f\u043e\u043b\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0441\u043b\u0435 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u0438\u043c\u0435\u044e\u0442 \u0440\u0430\u0437\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f         \"\"\"         self._msg += f\"{self._where} \u0432 json \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043f\u043e\u043b\u044f \u043d\u0435 \u0441\u043e\u0432\u043f\u0430\u043b\u0438 \u0441 \u044d\u0442\u0430\u043b\u043e\u043d\u043e\u043c:\\n\"         for key, value in diff.items():             self._msg += f\"\u043a\u043b\u044e\u0447: {value['path']}\\n\\t\\texpected: {value['expected']} \\n\\t\\tactual: {value['actual']}\\n\"         return self   class CodeLogMsg(LogMsg):     \"\"\"     \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0432 \u043b\u043e\u0433\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043a\u043e\u0434\u0430 \u043e\u0442\u0432\u0435\u0442\u0430.     \"\"\"      def __init__(self, response):         super().__init__('\u0412 \u041a\u041e\u0414\u0415 \u041e\u0422\u0412\u0415\u0422\u0410', response)      def add_compare_result(self, exp, <\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-356728","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/356728","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=356728"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/356728\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=356728"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=356728"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=356728"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}