{"id":346259,"date":"2023-03-04T15:00:50","date_gmt":"2023-03-04T15:00:50","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=346259"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=346259","title":{"rendered":"<span>\u0415\u0449\u0435 \u0440\u0430\u0437 \u043f\u0440\u043e \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 ASP.NET Core c testserver \u0438 testcontainers<\/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-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0425\u0430\u0431\u0440, \u043f\u0440\u0438\u0432\u0435\u0442!<\/p>\n<p>  <\/p>\n<p>\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u044f \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u0441\u043e\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u0430 \u0442\u0435\u043c\u0443 &#171;\u043a\u0430\u043a \u043d\u0430\u043c \u043e\u0431\u0443\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u0432\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0435\u0433\u043e \u0432 \u0441\u0438\u0430\u0439\u043a\u0443&#187;.<br \/>  \u041d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u044d\u0442\u0443 \u0437\u0430\u043c\u0435\u0442\u043a\u0443 \u043c\u0435\u043d\u044f \u0441\u043f\u043e\u0434\u0432\u0438\u0433\u043b\u0430 \u0434\u0438\u0441\u043a\u0443\u0441\u0441\u0438\u044f, \u0441\u043b\u0443\u0447\u0438\u0432\u0448\u0430\u044f\u0441\u044f \u043d\u0435\u0434\u0430\u0432\u043d\u043e \u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u0435. \u0418\u043d\u0438\u0446\u0438\u0430\u0442\u0438\u0432\u043d\u0430\u044f \u0433\u0440\u0443\u043f\u043f\u0430 &#171;\u0447\u0435\u0442\u044b\u0440\u0435\u0445\u0433\u043b\u0430\u0437\u044b\u0445 \u0432 \u0441\u0432\u0438\u0442\u0435\u0440\u0430\u0445&#187; \u043f\u044b\u0442\u0430\u043b\u0430\u0441\u044c \u0440\u043e\u0434\u0438\u0442\u044c \u043c\u0435\u0440\u044b \u043f\u043e \u0443\u043b\u0443\u0447\u0448\u0435\u043d\u0438\u044e \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430 \u043d\u0430\u0448\u0435\u0433\u043e \u0438\u0437\u0434\u0435\u043b\u0438\u044f \u0438 \u0441\u043d\u0438\u0436\u0435\u043d\u0438\u044f \u0442\u0440\u0443\u0434\u043e\u0437\u0430\u0442\u0440\u0430\u0442 QA-\u0438\u043d\u0436\u0435\u043d\u0435\u0440\u043e\u0432 \u043d\u0430 \u043f\u0440\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0440\u0443\u0442\u0438\u043d\u043d\u043e\u0433\u043e \u0440\u0435\u0433\u0440\u0435\u0441\u0441\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. \u041a\u0430\u043a \u044d\u0442\u043e \u0447\u0430\u0441\u0442\u043e \u0431\u044b\u0432\u0430\u0435\u0442, \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0435\u0441\u043b\u0438 \u0438 \u043f\u0438\u0441\u0430\u043b\u0438 \u0442\u0435\u0441\u0442\u044b, \u0442\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043c\u043e\u0434\u0443\u043b\u044c\u043d\u044b\u0435, \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u0438 end-to-end \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0449\u0438\u043a\u043e\u0432. \u0414\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f QA-\u0438\u043d\u0436\u0435\u043d\u0435\u0440\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 &#171;\u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u0441\u0442\u0435\u043d\u0434&#187;, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044b \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f (\u0435\u0449\u0435 \u043e\u043a\u043e\u043b\u043e 40, \u0441 \u043f\u043e\u0437\u0432\u043e\u043b\u0435\u043d\u0438\u044f \u0441\u043a\u0430\u0437\u0430\u0442\u044c, &#171;\u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432&#187;), \u0441\u0435\u0440\u0432\u0435\u0440 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 (\u0441 \u043d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u044f\u0441\u043d\u044b\u043c \u043d\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435\u043c \u044d\u0442\u043e\u0439 \u0441\u0430\u043c\u043e\u0439 \u0431\u0430\u0437\u044b), \u0431\u0440\u043e\u043a\u0435\u0440 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 (RabbitMQ) \u0438 \u0432\u0441\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435, \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041d\u0430 \u044d\u0442\u043e\u0442 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u0441\u0442\u0435\u043d\u0434 \u043d\u0430\u0442\u0440\u0430\u0432\u043b\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0448\u0430\u0442\u0430\u044e\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0437\u0430 \u0432\u0441\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u0441\u043d\u0430\u0440\u0443\u0436\u0438 \u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0435 \u0442\u043e\u0447\u043a\u0438, \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0411\u0414 \u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b UI \u043f\u044b\u0442\u0430\u044f\u0441\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u0432 \u0432 \u0433\u0440\u0430\u043d\u0438\u0446\u0430\u0445 (\u0438 \u0437\u0430 \u043d\u0438\u043c\u0438!) \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0445 \u0432\u0445\u043e\u0434\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p><a name=\"habracut\"><\/a>  <\/p>\n<p>\u0421\u0445\u0435\u043c\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0435 \u043e\u0442\u043b\u0438\u0447\u0430\u0435\u0442\u0441\u044f \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u044e, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u044f \u043d\u0435 \u0441\u0438\u043b\u044c\u043d\u043e \u043e\u0448\u0438\u0431\u0443\u0441\u044c, \u0435\u0441\u043b\u0438 \u0441\u043a\u0430\u0436\u0443, \u0447\u0442\u043e \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043c\u043e\u0436\u043d\u043e \u043b\u0435\u0433\u043a\u043e \u0432\u0441\u0442\u0440\u0435\u0442\u0438\u0442\u044c \u0432 \u0431\u043e\u043b\u044c\u0448\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432, \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043f\u043e\u043a\u0430 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432 \u0441\u0442\u0430\u0434\u0438\u0438 \u0432\u0437\u0440\u0430\u0449\u0438\u0432\u0430\u043d\u0438\u044f \u0441\u0432\u043e\u0438\u0445 \u043f\u0440\u0430\u043a\u0442\u0438\u043a. \u0421\u043e \u0432\u0441\u0435\u043c\u0438 \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u044b\u043c\u0438 \u043f\u043b\u044e\u0441\u0430\u043c\u0438 (\u043f\u0440\u043e\u0441\u0442\u043e\u0442\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u043f\u043e\u043d\u044f\u0442\u043d\u043e\u0441\u0442\u044c \u0438 \u043f\u0440\u043e\u0437\u0440\u0430\u0447\u043d\u043e\u0441\u0442\u044c \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439, \u043c\u043d\u043e\u0433\u043e\u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0441\u0442\u0435\u043d\u0434\u0430 \u2014 \u043c\u043e\u0436\u043d\u043e \u0436\u0435 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u044b \u043f\u043e\u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c, \u043d\u043e \u0438 \u0434\u043b\u044f \u0434\u0435\u043c\u043e \u043f\u043e\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c) \u044d\u0442\u043e\u0442 \u043f\u043e\u0434\u0445\u043e\u0434 \u0438\u043c\u0435\u0435\u0442 \u0438 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u043c\u0438\u043d\u0443\u0441\u044b:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u043e\u0442\u0440\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043e\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0432 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u0432\u0435\u0434\u044c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0435\u0435 \u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u043c \u0441\u0442\u0435\u043d\u0434\u0435 \u044d\u0442\u043e \u0437\u0430\u0431\u043e\u0442\u0430 QA<\/li>\n<li>\u043e\u0431\u0449\u0438\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 (\u0411\u0414, Redis, \u0431\u0440\u043e\u043a\u0435\u0440\u044b) \u043d\u0430\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u043e\u0441\u0442\u0430\u0442\u043a\u0430\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u0432, \u0447\u0442\u043e \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u0438\u0445 \u0440\u0430\u0437\u0434\u0443\u0432\u0430\u043d\u0438\u044e \u0438\u043b\u0438 \u0432 \u0445\u0443\u0434\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u043d\u0435\u0436\u0435\u043b\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u044b <\/li>\n<li>QA \u0442\u0440\u0430\u0442\u044f\u0442 \u043c\u043d\u043e\u0433\u043e \u0441\u0438\u043b \u043d\u0430 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u0441\u0442\u0435\u043d\u0434\u0430 \u0432 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 (\u043a\u043e\u0433\u0434\u0430 \u0442\u0432\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0431\u043e\u043b\u0435\u0435 40 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0441 \u0437\u0430\u043f\u0443\u0442\u0430\u043d\u043d\u044b\u043c\u0438 \u0441\u0432\u044f\u0437\u044f\u043c\u0438 \u043c\u0435\u0436\u0434\u0443 \u043d\u0438\u043c\u0438, \u0430 \u043a\u043e\u043c\u0430\u043d\u0434 \u0431\u043e\u043b\u044c\u0448\u0435 \u0447\u0435\u043c \u043e\u0434\u043d\u0430 \u2014 \u044d\u0442\u043e \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0435\u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0435\u0439)<br \/>  \u0412\u0441\u0451 \u044d\u0442\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u0441\u0442\u0432\u0443\u0435\u0442 \u0440\u043e\u0441\u0442\u0443 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 false-positive \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u043d\u0438\u0439, \u0447\u0442\u043e \u0432 \u0438\u0442\u043e\u0433\u0435 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0432 \u0433\u043e\u0440\u044f\u0447\u0438\u0435 \u043c\u043e\u043c\u0435\u043d\u0442\u044b \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0440\u0435\u043b\u0438\u0437\u044b \u043c\u043e\u0433\u0443\u0442 \u043f\u043e\u0435\u0445\u0430\u0442\u044c \u0432 \u043f\u0440\u043e\u0434 \u0431\u0435\u0437 \u0434\u043e\u043b\u0436\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f.<br \/>  \u041d\u0443 \u0434\u0430 \u0445\u0432\u0430\u0442\u0438\u0442 \u0441\u043b\u043e\u0432, \u0441\u043a\u043e\u0440\u0435\u0435 \u043a \u0434\u0435\u043b\u0443. \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u0435\u0441\u0435\u043b\u044b\u043c \u0441\u043d\u043e\u0432\u0430.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u041e\u0431\u044a\u0435\u043a\u0442\u043e\u043c \u0441\u0435\u0433\u043e\u0434\u043d\u044f\u0448\u043d\u0438\u0445 \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0439 \u0441\u0442\u0430\u043d\u0435\u0442 \u043f\u0440\u043e\u0441\u0442\u043e\u0435 asp.net core web api \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0441 \u043e\u0434\u043d\u0438\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u043c \u0441 \u043d\u0430\u0431\u043e\u0440\u043e\u043c CRUD \u043c\u0435\u0442\u043e\u0434\u043e\u0432. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 out-of-process \u0437\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0431\u044b\u043b\u043e \u0431\u044b \u0441\u043b\u043e\u0436\u043d\u043e \u0437\u0430\u043c\u043e\u043a\u0430\u0442\u044c, \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0411\u0414 (\u043c\u044b \u0433\u043e\u0432\u043e\u0440\u0438\u043c \u0411\u0414 \u2014 \u043f\u043e\u0434\u0440\u0430\u0437\u0443\u043c\u0435\u0432\u0430\u0435\u043c Postgres).<br \/>  \u0414\u0435\u043c\u043e-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043e\u0442\u043b\u0438\u0447\u0430\u0435\u0442\u0441\u044f \u043e\u0442 \u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c\u043e\u0433\u043e \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 <code>dotnet new webapi<\/code> \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u043b\u0438\u0447\u0438\u0435\u043c ef core, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0437\u0434\u0435\u0441\u044c \u044f \u0432\u0435\u0441\u044c \u043b\u0438\u0441\u0442\u0438\u043d\u0433 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442\u044c \u043d\u0435 \u0431\u0443\u0434\u0443\u0442 \u2014 \u0432\u0435\u0440\u0441\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043e \u043d\u0430\u0447\u0430\u043b\u0430 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f <a href=\"https:\/\/github.com\/zetroot\/TestHostTestContainers\/tree\/v0\" rel=\"nofollow noopener noreferrer\">\u043e\u0442\u043c\u0435\u0447\u0435\u043d\u0430 \u0442\u0435\u0433\u043e\u043c<\/a> <code>v0<\/code> \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438.<br \/>  \u0412 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0440\u0430\u0437\u0434\u0435\u043b\u0430\u0445 \u044f \u043f\u0440\u043e\u0439\u0434\u0443 \u043f\u0443\u0442\u044c \u043e\u0442 \u043d\u0430\u0438\u0432\u043d\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u043a \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u043c \u0442\u0435\u0441\u0442\u0430\u043c \u0434\u043e stateless \u0442\u0435\u0441\u0442\u043e\u0432 \u0441 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438, \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c\u044b\u043c\u0438 \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430\u0445.<\/p>\n<p>  <\/p>\n<h2 id=\"naivnyy-podhod\">&#171;\u041d\u0430\u0438\u0432\u043d\u044b\u0439&#187; \u043f\u043e\u0434\u0445\u043e\u0434<\/h2>\n<p>  <\/p>\n<p>\u0421 \u0441\u0430\u043c\u043e\u0433\u043e \u043d\u0430\u0447\u0430\u043b\u0430, \u0441 \u043c\u043e\u043c\u0435\u043d\u0442\u0430, \u043a\u043e\u0433\u0434\u0430 \u044f \u0437\u0430\u0434\u0443\u043c\u0430\u043b \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u044d\u0442\u0443 \u0437\u0430\u043c\u0435\u0442\u043a\u0443, \u044f \u0445\u043e\u0442\u0435\u043b \u043d\u0430\u0437\u0432\u0430\u0442\u044c \u044d\u0442\u043e\u0442 \u043f\u043e\u0434\u0445\u043e\u0434 &#171;\u043d\u0430\u0438\u0432\u043d\u044b\u043c&#187; \u0438\u043b\u0438 &#171;\u0432 \u043b\u043e\u0431&#187;. \u041d\u043e, \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u0432 \u043b\u043e\u0431 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0432\u044b\u0448\u043b\u043e \u0438 \u043c\u043d\u0435 \u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043b\u043e\u0441\u044c \u043e\u043a\u043e\u043b\u043e \u0434\u0432\u0443\u0445 \u0447\u0430\u0441\u043e\u0432 \u043b\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0432 \u043e\u0442\u043a\u0440\u044b\u0442\u0443\u044e \u0434\u0432\u0435\u0440\u044c, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u044f \u043d\u0435 \u043c\u043e\u0433 \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c. \u0412\u0441\u0435 \u0432\u044b\u0437\u043e\u0432\u044b \u043a \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430\u043c \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u043b\u0438\u0441\u044c \u043d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u043b\u0438 404. \u0427\u0442\u043e\u0431\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430\u0448\u043b\u043e \u0441\u0432\u043e\u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b \u0432 \u043a\u043e\u0434 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 DI \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0432\u043d\u043e\u0441\u0438\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u044b \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u043b\u0438 \u0437\u0430\u0434\u0443\u043c\u0430\u0442\u044c\u0441\u044f, \u043e \u0440\u0430\u0437\u0443\u043c\u043d\u043e\u0441\u0442\u0438 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439. \u0422\u0430\u043a \u0447\u0442\u043e \u0434\u043b\u044f \u044f\u0441\u043d\u043e\u0441\u0442\u0438 \u044f \u0432\u043e\u0437\u044c\u043c\u0443 \u0441\u043b\u043e\u0432\u043e &#171;\u043d\u0430\u0438\u0432\u043d\u044b\u0439&#187; \u0432 \u043a\u0430\u0432\u044b\u0447\u043a\u0438.<br \/>  \u0412 \u0447\u0435\u043c \u0441\u0443\u0442\u044c \u043f\u043e\u0434\u0445\u043e\u0434\u0430: \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u0435\u0441\u044f \u0432 test-runner &#171;\u043a\u0430\u043a \u0435\u0441\u0442\u044c&#187; \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0440\u0435\u0430\u043b\u044c\u043d\u0443\u044e \u0411\u0414 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0443\u044e \u0438\u0437 \u0430\u0433\u0435\u043d\u0442\u0430 CI (\u044d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043a\u0430\u043a \u0440\u0430\u0437 \u0411\u0414 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u0441\u0442\u0435\u043d\u0434\u0430 \u0438\u043b\u0438 \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0430\u043d\u0441 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u0434\u043b\u044f CI). \u0418\u043d\u044b\u0435 out-of-process \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0442\u0430\u043a \u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0435 \u0441 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u0441\u0442\u0435\u043d\u0434\u0430.<br \/>  \u0412 \u0441\u0432\u044f\u0437\u0438 \u0441 \u0442\u0435\u043c, \u0447\u0442\u043e \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u0440\u043e\u0433\u043e\u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u043e\u0439 \u0441\u0431\u043e\u0440\u043a\u043e\u0439 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u0431\u043e\u0440\u043a\u0430 \u0441 \u0442\u0435\u0441\u0442\u0430\u043c\u0438, \u0430 \u043d\u0435 \u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0440\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 DI \u044f\u0432\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c, \u0447\u0442\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0438\u0441\u043a\u0430\u0442\u044c \u0432 \u0441\u0431\u043e\u0440\u043a\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">builder.Services.AddMvc()     .AddApplicationPart(typeof(Program).Assembly)     .AddControllersAsServices(); builder.Services.AddControllers(); <\/code><\/pre>\n<p>  <\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u043e\u0432. \u0414\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430\u0434\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u0434\u0430\u0441\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u043e\u0441\u0443\u0442\u043f \u043a \u0435\u0433\u043e DI \u0438 \u0432\u044b\u0434\u0435\u0440\u043d\u0443\u0442\u044c \u0438\u0437 \u043d\u0435\u0433\u043e <code>DbContext<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 side-\u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432 (\u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0411\u0414).<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">private WebApplication _app = null!; private DataContext _context = null!; private HttpClient _client = null!; private IDataClient _refitClient = null!; private IServiceScope _scope = null!;  [SetUp] public async Task Setup() {     var builder = WebApplication.CreateBuilder()         .ConfigureServices();     _app = builder.CreateApplication();     _app.Urls.Add(\"http:\/\/*:8080\");     await _app.StartAsync();     _scope = _app.Services.CreateScope();     _context = _scope.ServiceProvider.GetRequiredService&lt;DataContext>();     _client = new HttpClient { BaseAddress = new Uri(\"http:\/\/localhost:8080\") };     _refitClient = RestService.For&lt;IDataClient>(_client); }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0422\u0430\u043a \u0436\u0435 \u043f\u0440\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f http-\u043a\u043b\u0438\u0435\u043d\u0442 (<code>_client<\/code>), \u043d\u0430\u0446\u0435\u043b\u0435\u043d\u043d\u044b\u0439 \u043d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438 \u0442\u0438\u043f\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 refit-\u043a\u043b\u0438\u0435\u043d\u0442 (<code>_refitClient<\/code>), \u0434\u043b\u044f \u0432\u044b\u0437\u043e\u0432\u0430 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u0432 \u043f\u043e \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443.<br \/>  \u041f\u043e\u0441\u043b\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u043e\u0432 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438 \u043e\u0441\u0432\u043e\u0431\u043e\u0434\u0438\u0442\u044c \u0440\u0435\u0441\u0443\u0440\u0441\u044b \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0435 \u0434\u043b\u044f http-\u043a\u043b\u0438\u0435\u043d\u0442\u0430:<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">[TearDown] public async Task TearDown() {     _scope.Dispose();     await _app.StopAsync();     _client.Dispose(); } <\/code><\/pre>\n<p>  <\/p>\n<p>\u041a\u043e\u0433\u0434\u0430 \u0432\u0441\u044f \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432 \u043f\u043e\u0434\u043d\u044f\u0442\u0430, \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0434\u0435\u043b\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043b\u043e\u0433\u0438\u043a\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">[Test] public async Task PostData_WhenCalled_Returns200() {     \/\/act     var response = await _client.PostAsJsonAsync(new Uri(\"data\", UriKind.Relative), \"test\");     \/\/assert     response.StatusCode.Should().Be(HttpStatusCode.OK); }  [Test] public async Task PostData_WhenCalled_ReturnsIdOfAddedRecord() {     \/\/arrange     var cntBefore = await _context.Set&lt;UserData>().CountAsync();     \/\/act     var id = await _refitClient.Create(\"test creation\");     \/\/assert     _context.Set&lt;UserData>().Count().Should().BeGreaterThan(cntBefore);     _context.Set&lt;UserData>().Any(x => x.Id == id).Should().BeTrue();     _context.Set&lt;UserData>().Single(x => x.Id == id).Data.Should().Be(\"test creation\"); }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0446\u0435\u043b\u044c \u0434\u043e\u0441\u0442\u0438\u0433\u043d\u0443\u0442\u0430: \u0442\u0435\u0441\u0442\u044b \u043f\u0440\u043e\u0445\u043e\u0434\u044f\u0442, \u043c\u043e\u0436\u043d\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0435 http \u0437\u0430\u043f\u0440\u043e\u0441\u044b, \u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f, \u0435\u0441\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043d\u0435\u0439 \u0438\u0437 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u043a\u043b\u0430\u0441\u0441\u043e\u0432. \u041d\u043e \u0435\u0441\u0442\u044c \u0438 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0440\u0435\u0430\u043b\u044c\u043d\u0430\u044f \u0411\u0414, \u043a\u0440\u0435\u0434\u044b \u043a \u043d\u0435\u0439 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438 \u0438\u043b\u0438 \u043f\u043e\u0434\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0442\u044c \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f<\/li>\n<li>\u0442\u0430\u043a \u0436\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u043d\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0411\u0414 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0438 \u043e\u0447\u0438\u0441\u0442\u043a\u0443 \u043f\u043e\u0441\u043b\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u0442\u0435\u0441\u0442\u043e\u0432<\/li>\n<li>\u043d\u0430\u0434\u043e \u0431\u044b\u0442\u044c \u0443\u0432\u0435\u0440\u0435\u043d\u043d\u044b\u043c, \u0447\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0439 \u043f\u043e\u0440\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 test-runner \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d<br \/>  \u041a\u043e\u0434 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 \u044d\u0442\u0438\u043c\u0438 \u0442\u0435\u0441\u0442\u0430\u043c\u0438 <a href=\"https:\/\/github.com\/zetroot\/TestHostTestContainers\/tree\/v1\" rel=\"nofollow noopener noreferrer\">\u043e\u0442\u043c\u0435\u0447\u0435\u043d \u0442\u0435\u0433\u043e\u043c<\/a> <code>v1<\/code>.<\/li>\n<\/ul>\n<p>  <\/p>\n<h2 id=\"testserver\">Testserver<\/h2>\n<p>  <\/p>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0448\u0430\u0433 \u2014 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 ASP.NET Core \u0434\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. \u0417\u0430\u043c\u0435\u043d\u0438\u043c kestrel \u043d\u0430 test server!<br \/>  \u0414\u043b\u044f \u0443\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a DI \u0438 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u0435\u043d\u0438\u044f \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0446\u0438\u0439 \u0441 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u043c \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u043c \u043d\u0430\u0441\u043b\u0435\u0434\u043d\u0438\u043a\u0430 <code>WebApplicationFactory&lt;><\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public class CustomAppFactory : WebApplicationFactory&lt;Program> {     protected override void ConfigureWebHost(IWebHostBuilder builder)     {         builder.ConfigureTestServices(services =>         {             \/\/ \u0423\u0434\u0430\u043b\u0438\u043c \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 DataContext             var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions&lt;DataContext>));             if (descriptor != null)                 services.Remove(descriptor);              \/\/ \u0417\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u043c \u0441\u043d\u043e\u0432\u0430 \u0441 \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u0435\u043c \u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432\u0443\u044e \u0411\u0414             services.AddDbContextPool&lt;DataContext>(opts => opts.UseNpgsql(\"Host=localhost;Database=test_ci_db;Username=postgres;Password=;\"));              \/\/ \u041e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u043c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0411\u0414             var serviceProvider = services.BuildServiceProvider();             using var scope = serviceProvider.CreateScope();             var scopedServices = scope.ServiceProvider;             var context = scopedServices.GetRequiredService&lt;DataContext>();             context.Database.EnsureDeleted();             context.Database.EnsureCreated();             \/\/ \u0417\u0434\u0435\u0441\u044c \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043a\u043e\u0434 \"\u043d\u0430\u043f\u043e\u043b\u043d\u044f\u044e\u0449\u0438\u0439\" \u0411\u0414 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438...         });     } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u042d\u0442\u0430 \u0444\u0430\u0431\u0440\u0438\u043a\u0430 \u0438 \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0442\u044c \u0437\u0430\u043f\u0443\u0441\u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041c\u0435\u0442\u043e\u0434 <code>ConfigureTestServices<\/code> \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0441\u043b\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 DI \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 \u043d\u0435\u043c \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0438 \u043d\u0430\u0446\u0435\u043b\u0438\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0430\u043d\u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0411\u0414, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0439 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u044b\u0445 \u0432 CI.<br \/>  \u041a\u043e\u0434 \u0442\u0435\u0441\u0442\u043e\u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442\u0441\u044f. \u041f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0444\u0430\u0431\u0440\u0438\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u0435\u0440\u0432\u0438\u0441\u044b \u0438\u0437 DI-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u0438 \u0433\u043e\u0442\u043e\u0432\u044b\u0439 http-\u043a\u043b\u0438\u0435\u043d\u0442, \u043d\u0430\u0446\u0435\u043b\u0435\u043d\u043d\u044b\u0439 \u043d\u0430 \u0442\u0435\u0441\u0438\u0442\u0440\u0443\u0435\u043c\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435:<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">private CustomAppFactory _factory = new(); private DataContext _context = null!; private HttpClient _client = null!; private IDataClient _refitClient = null!; private IServiceScope _scope = null!;  [SetUp] public void Setup() {     _scope = _factory.Services.CreateScope();     _context = _scope.ServiceProvider.GetRequiredService&lt;DataContext>();     _client = _factory.CreateClient();     _refitClient = RestService.For&lt;IDataClient>(_client); }  [TearDown] public void TearDown() {     _scope.Dispose();     _client.Dispose(); }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041a\u043e\u0434 \u0441\u0430\u043c\u0438\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 \u043d\u0435 \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f. \u042d\u0442\u043e\u0442 \u044d\u0442\u0430\u043f \u0440\u0430\u0437\u0432\u0438\u0442\u0438\u044f \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f <a href=\"https:\/\/github.com\/zetroot\/TestHostTestContainers\/tree\/v2\" rel=\"nofollow noopener noreferrer\">\u043e\u0442\u043c\u0435\u0447\u0435\u043d \u0442\u0435\u0433\u043e\u043c<\/a> <code>v2<\/code> \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438.<br \/>  \u0427\u0442\u043e \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u043d\u0430 \u0442\u0435\u043a\u0443\u0449\u0435\u043c \u044d\u0442\u0430\u043f\u0435:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u043d\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f kestrel<\/li>\n<li>\u0435\u0441\u0442\u044c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u043d\u0430\u0434 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u043e\u0439 \u0411\u0414 <\/li>\n<li>\u0435\u0441\u0442\u044c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u043d\u0430\u0434 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u043e\u043a\u0438 \u0432\u043c\u0435\u0441\u0442\u043e \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0422\u0435\u043c \u043d\u0435 \u043c\u0435\u043d\u0435\u0435, \u0442\u0435\u0441\u0442\u0430\u043c \u0432\u0441\u0435 \u0435\u0449\u0435 \u043d\u0430\u0434\u043e \u0438\u043c\u0435\u0442\u044c \u0432\u043d\u0435\u0448\u043d\u044e\u044e \u0411\u0414 \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 out-of-process \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438. \u0422\u0430\u043a \u0447\u0442\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043d\u0430 CI \u0432\u0441\u0435 \u0435\u0449\u0435 \u043d\u0435\u043b\u044c\u0437\u044f \u043d\u0430\u0437\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0430\u0432\u0442\u043e\u043d\u043e\u043c\u043d\u044b\u043c. <\/p>\n<p>  <\/p>\n<h2 id=\"testovye-konteynery\">\u0422\u0435\u0441\u0442\u043e\u0432\u044b\u0435 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b<\/h2>\n<p>  <\/p>\n<p>\u0427\u0442\u043e \u0436, \u0438 \u0434\u043b\u044f \u044d\u0442\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0435\u0441\u0442\u044c \u0440\u0435\u0448\u0435\u043d\u0438\u0435. \u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043f\u0440\u043e\u0435\u043a\u0442 <a href=\"https:\/\/dotnet.testcontainers.org\/\" rel=\"nofollow noopener noreferrer\">Testcontainers<\/a>, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439, \u043f\u043e \u0438\u0445 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u0441\u043b\u043e\u0432\u0430\u043c, \u043b\u0435\u0433\u043a\u043e\u0432\u0435\u0441\u043d\u044b\u0435, \u043e\u0434\u043d\u043e\u0440\u0430\u0437\u043e\u0432\u044b\u0435 \u044d\u043a\u0437\u0435\u043c\u043b\u044f\u0440\u044b \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439. \u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u043f\u043e\u0432\u0435\u0440\u0445 Docker remote API \u0438 \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b \u0438\u0437 \u043b\u044e\u0431\u044b\u0445 \u043e\u0431\u0440\u0430\u0437\u043e\u0432 \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0438\u0445 \u0432 \u0442\u0435\u0441\u0442\u0430\u0445.<\/p>\n<p>  <\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u043d\u0435 \u0431\u043e\u0440\u043e\u0442\u044c\u0441\u044f \u0437\u0430 \u043f\u043e\u0440\u0442\u044b \u0438 hostnames \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0438\u0445 \u0432 \u0444\u0430\u0431\u0440\u0438\u043a\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0447\u0435\u0440\u0435\u0437 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b:<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public class CustomAppFactory : WebApplicationFactory&lt;Program> {     private readonly string _dbConnStr;      public CustomAppFactory(string host, int port, string password)     {         var sb = new NpgsqlConnectionStringBuilder         {             Host = host, Port = port, Database = \"test_ci_database\", Username = \"postgres\", Password = password         };         _dbConnStr = sb.ConnectionString;     }      protected override void ConfigureWebHost(IWebHostBuilder builder)     {         builder.ConfigureTestServices(services =>         {             \/\/ ...             services.AddDbContextPool&lt;DataContext>(opts => opts.UseNpgsql(_dbConnStr));             \/\/ ...         });     } } <\/code><\/pre>\n<p>  <\/p>\n<p>\u0418 \u0432 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0441 \u043f\u043e\u0441\u0442\u0433\u0440\u0435\u0441\u043e\u043c:<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">[OneTimeSetUp] public async Task SetupContainer() {     const string postgresPwd = \"pgpwd\";      _pgContainer = new ContainerBuilder()         .WithName(Guid.NewGuid().ToString(\"N\"))         .WithImage(\"postgres:15\")         .WithHostname(Guid.NewGuid().ToString(\"N\"))         .WithExposedPort(5432)         .WithPortBinding(5432, true)         .WithEnvironment(\"POSTGRES_PASSWORD\", postgresPwd)         .WithEnvironment(\"PGDATA\", \"\/pgdata\")         .WithTmpfsMount(\"\/pgdata\")         .WithWaitStrategy(Wait.ForUnixContainer().UntilCommandIsCompleted(\"psql -U postgres -c \\\"select 1\\\"\"))         .Build();     await _pgContainer.StartAsync();      _factory = new(_pgContainer.Hostname, _pgContainer.GetMappedPublicPort(5432), postgresPwd); }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0418\u0437 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0435\u0439: \u0438\u043c\u044f \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u0438 \u0438\u043c\u044f \u0445\u043e\u0441\u0442\u0430 \u0432\u044b\u0431\u0438\u0440\u0430\u044e\u0442\u0441\u044f \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e (\u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u043c \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c <code>Guid.NewGuid()<\/code>), \u043f\u043e\u0440\u0442 \u043f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043a \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e\u043c\u0443 \u0432\u043d\u0435\u0448\u043d\u0435\u043c\u0443 \u043f\u043e\u0440\u0442\u0443. \u0412\u0441\u0435 \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442\u0441\u044f, \u0447\u0442\u043e\u0431\u044b \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0441 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u044d\u043a\u0437\u0435\u043f\u043b\u044f\u0440\u0430\u043c\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043c\u0438 \u0442\u0435\u0441\u0442\u043e\u0432 \u043d\u0430 \u0442\u043e\u0439 \u0436\u0435 \u043c\u0430\u0448\u0438\u043d\u0435.<br \/>  \u0421\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0438\u043c\u0435\u043d\u0430 \u0438 \u043f\u043e\u0440\u0442\u044b \u043b\u0435\u0433\u043a\u043e \u0438\u0437\u0432\u043b\u0435\u0447\u044c \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0432 \u0444\u0430\u0431\u0440\u0438\u043a\u0443 \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 SUT.<br \/>  \u0422\u0430\u043a \u0436\u0435 \u043e\u0431\u0440\u0430\u0449\u0443 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u043b\u0430\u0439\u0444\u0445\u0430\u043a \u2014 <code>.WithEnvironment(\"PGDATA\", \"\/pgdata\")<\/code> \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u0441\u0443\u0431\u0434 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0431\u0430\u0437 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e \u043f\u0443\u0442\u0438 <code>\/pgdata<\/code> \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u0430\u043f\u043f\u0438\u0442\u0441\u044f \u0432 \u043f\u0430\u043c\u044f\u0442\u044c \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 <code>.WithTmpfsMount(\"\/pgdata\")<\/code>. \u0422\u0430\u043a \u0447\u0442\u043e \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u0442\u0435\u0441\u0442\u043e\u0432 \u0431\u0443\u0434\u0435\u0442 \u043c\u043d\u043e\u0433\u043e, \u0438\u043b\u0438 \u0432 \u0445\u043e\u0434\u0435 \u0442\u0435\u0441\u0442\u043e\u0432 \u0431\u0443\u0434\u0443\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0442\u044f\u0436\u0435\u043b\u044b\u0435 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u2014 \u043c\u0435\u0441\u0442\u043e \u043d\u0430 \u0434\u0438\u0441\u043a\u0435 \u043d\u0435 \u043f\u043e\u0441\u0442\u0440\u0430\u0434\u0430\u0435\u0442, \u0411\u0414 \u0431\u0443\u0434\u0435\u0442 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e in-memory.<br \/>  \u0412\u0442\u043e\u0440\u043e\u0439 \u043b\u0430\u0439\u0444\u0445\u0430\u043a \u2014 \u043f\u0435\u0440\u0435\u0434 \u0442\u0435\u043c \u043a\u0430\u043a \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u043d\u0430\u0434\u043e \u0434\u043e\u0436\u0434\u0430\u0442\u044c\u0441\u044f \u043a\u043e\u0433\u0434\u0430 PG \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043f\u043e\u0434\u043d\u0438\u043c\u0435\u0442\u0441\u044f \u0438 \u0431\u0443\u0434\u0435\u0442 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u0430. \u041c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u044f \u0445\u0435\u043b\u0441\u0447\u0435\u043a\u0438 \u0432 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u043e\u043c dockerfile, \u0430 \u043c\u043e\u0436\u043d\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432\u044b\u0437\u043e\u0432\u0430\u043c\u0438 testcontainers: <code>.WithWaitStrategy(Wait.ForUnixContainer().UntilCommandIsCompleted(\"psql -U postgres -c \\\"select 1\\\"\"))<\/code>. \u0417\u0434\u0435\u0441\u044c \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0449\u0435\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043e\u0436\u0434\u0435\u0442\u0441\u044f, \u043f\u043e\u043a\u0430 \u0411\u0414 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043e\u0436\u0438\u0432\u0435\u0442 \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u0441\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0430 <code>select 1<\/code>, \u0447\u0442\u043e \u0438 \u0431\u0443\u0434\u0435\u0442 \u043e\u0437\u043d\u0430\u0447\u0430\u0442\u044c \u0433\u043e\u0442\u043e\u0432\u043d\u043e\u0441\u0442\u044c \u0411\u0414 \u043a \u043d\u0430\u0448\u0438\u043c \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c.<br \/>  \u041f\u043e\u0441\u043b\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u0435 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u0431\u0440\u043e\u0441\u0438\u0442\u044c:<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">[OneTimeTearDown] public async Task DisposeContainer() =>         await _pgContainer.DisposeAsync();<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412\u043e\u0442 \u0442\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0432 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e stateless \u043c\u0430\u043d\u0435\u0440\u0435, \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043d\u0438\u043a\u0430\u043a\u043e\u0439 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f. \u0412\u0441\u0435 \u0447\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0434\u043b\u044f \u043f\u0440\u043e\u0433\u043e\u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u2014 \u044d\u0442\u043e dotnet sdk \u0438 docker.<br \/>  \u041a\u043e\u0434 \u044d\u0442\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f <a href=\"https:\/\/github.com\/zetroot\/TestHostTestContainers\/tree\/v3\" rel=\"nofollow noopener noreferrer\">\u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043f\u043e\u0434 \u0442\u0435\u0433\u043e\u043c<\/a> <code>v3<\/code><\/p>\n<p>  <\/p>\n<h3 id=\"zapusk-v-ci\">\u0417\u0430\u043f\u0443\u0441\u043a \u0432 CI<\/h3>\n<p>  <\/p>\n<p>\u0414\u043e \u044d\u0442\u043e\u0433\u043e \u0432\u0441\u0435 \u0440\u0430\u0437\u0433\u043e\u0432\u043e\u0440\u044b \u0431\u044b\u043b\u0438 \u043e CI, \u0430\u0433\u0435\u043d\u0442\u044b \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u0432 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u0443\u0435\u043c\u043e\u043c, \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u043c \u0434\u043b\u044f \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0438. \u041d\u043e Github Actions \u2014 \u043d\u0435 \u0442\u0430\u043a\u043e\u0439. \u041e\u043d \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0439 (\u043f\u043e \u043c\u0435\u0440\u0435 \u0432\u043e\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439), \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0439, \u043d\u043e \u0435\u0433\u043e \u0430\u0433\u0435\u043d\u0442\u044b \u0436\u0438\u0432\u0443\u0442 \u0433\u0434\u0435 \u0442\u043e \u0442\u0430\u043c \u0434\u0430\u043b\u0435\u043a\u043e \u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u043f\u043e\u0434\u043d\u044f\u0442\u044c \u0440\u044f\u0434\u043e\u043c \u0441 \u043d\u0430\u0448\u0438\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u043a\u0430\u043a\u0443\u044e \u0442\u043e \u0411\u0414 (\u043d\u0443 \u0445\u043e\u0442\u044f \u0431\u044b \u0411\u0414) \u2014 \u043d\u0435\u0442.<br \/>  \u0421 \u0442\u0435\u0441\u0442\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430\u043c\u0438 \u044d\u0442\u043e \u043d\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430!<br \/>  \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0448\u0430\u0431\u043b\u043e\u043d\u043d\u044b\u0439 github action:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">name: .NET  on:   push:     branches: [ \"master\" ]   pull_request:     branches: [ \"master\" ]   workflow_dispatch:  jobs:   build:      runs-on: ubuntu-latest      steps:     - uses: actions\/checkout@v3     - name: Setup .NET       uses: actions\/setup-dotnet@v3       with:         dotnet-version: 7.0.x     - name: Restore dependencies       run: dotnet restore     - name: Build       run: dotnet build --no-restore     - name: Test       run: dotnet test --no-build --verbosity normal <\/code><\/pre>\n<p>  <\/p>\n<p>\u0418 \u0432\u0441\u0435, \u0431\u0438\u043b\u0434 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442, <a href=\"https:\/\/github.com\/zetroot\/TestHostTestContainers\/actions\/runs\/4330729004\/jobs\/7562132598\" rel=\"nofollow noopener noreferrer\">\u0442\u0435\u0441\u0442\u044b \u0437\u0435\u043b\u0435\u043d\u044b\u0435<\/a>, \u043c\u044b \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043b\u0438 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0435 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u0442\u0435\u0441\u0442\u044b \u0432 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043c\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u043c \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c.<\/p>\n<p>  <\/p>\n<p>\u042d\u0442\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u044f <a href=\"https:\/\/github.com\/zetroot\/TestHostTestContainers\/tree\/v3.1\" rel=\"nofollow noopener noreferrer\">\u043e\u0442\u043c\u0435\u0442\u0438\u043b \u0442\u0435\u0433\u043e\u043c<\/a> <code>v3.1<\/code>.<\/p>\n<p>  <\/p>\n<h2 id=\"vmesto-zaklyucheniya\">\u0412\u043c\u0435\u0441\u0442\u043e \u0437\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f<\/h2>\n<p>  <\/p>\n<p>\u041d\u0443 \u0447\u0442\u043e, \u0432\u0441\u0435 \u0432\u0441\u0451 \u0441\u0430\u043c\u0438 \u0432\u0438\u0434\u0435\u043b\u0438, \u043c\u043e\u0436\u043d\u043e \u043f\u0438\u0441\u0430\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0435 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u0442\u0435\u0441\u0442\u044b \u0434\u043b\u044f asp.net core \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0449\u0438\u0445 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0435 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0435 \u0432\u043d\u0435\u0448\u043d\u0438\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0435 \u043a\u0430\u0441\u0430\u044f\u0441\u044c yaml \u043c\u0430\u0433\u0438\u0438 \u0438 \u043d\u0435 \u0432\u043d\u043e\u0441\u044f \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0432 \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u044b\u0439 CI\/CD \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d. \u041d\u0430\u0434\u0435\u044e\u0441\u044c \u044d\u0442\u0430 \u0437\u0430\u043c\u0435\u0442\u043a\u0430 \u0431\u044b\u043b\u0430 \u0445\u043e\u0440\u043e\u0448\u0435\u0439 \u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446\u0438\u0435\u0439 \u0438 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043a\u043e\u043c\u0443-\u0442\u043e \u043d\u0430\u0447\u0430\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u0442\u0435\u0441\u0442\u044b \u0432 \u0435\u0436\u0435\u0434\u043d\u0435\u0432\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u0435.<\/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\/post\/720420\/\"> https:\/\/habr.com\/ru\/post\/720420\/<\/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-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0425\u0430\u0431\u0440, \u043f\u0440\u0438\u0432\u0435\u0442!<\/p>\n<p>  <\/p>\n<p>\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u044f \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u0441\u043e\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u0430 \u0442\u0435\u043c\u0443 &#171;\u043a\u0430\u043a \u043d\u0430\u043c \u043e\u0431\u0443\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u0432\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0435\u0433\u043e \u0432 \u0441\u0438\u0430\u0439\u043a\u0443&#187;.<br \/>  \u041d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u044d\u0442\u0443 \u0437\u0430\u043c\u0435\u0442\u043a\u0443 \u043c\u0435\u043d\u044f \u0441\u043f\u043e\u0434\u0432\u0438\u0433\u043b\u0430 \u0434\u0438\u0441\u043a\u0443\u0441\u0441\u0438\u044f, \u0441\u043b\u0443\u0447\u0438\u0432\u0448\u0430\u044f\u0441\u044f \u043d\u0435\u0434\u0430\u0432\u043d\u043e \u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u0435. \u0418\u043d\u0438\u0446\u0438\u0430\u0442\u0438\u0432\u043d\u0430\u044f \u0433\u0440\u0443\u043f\u043f\u0430 &#171;\u0447\u0435\u0442\u044b\u0440\u0435\u0445\u0433\u043b\u0430\u0437\u044b\u0445 \u0432 \u0441\u0432\u0438\u0442\u0435\u0440\u0430\u0445&#187; \u043f\u044b\u0442\u0430\u043b\u0430\u0441\u044c \u0440\u043e\u0434\u0438\u0442\u044c \u043c\u0435\u0440\u044b \u043f\u043e \u0443\u043b\u0443\u0447\u0448\u0435\u043d\u0438\u044e \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430 \u043d\u0430\u0448\u0435\u0433\u043e \u0438\u0437\u0434\u0435\u043b\u0438\u044f \u0438 \u0441\u043d\u0438\u0436\u0435\u043d\u0438\u044f \u0442\u0440\u0443\u0434\u043e\u0437\u0430\u0442\u0440\u0430\u0442 QA-\u0438\u043d\u0436\u0435\u043d\u0435\u0440\u043e\u0432 \u043d\u0430 \u043f\u0440\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0440\u0443\u0442\u0438\u043d\u043d\u043e\u0433\u043e \u0440\u0435\u0433\u0440\u0435\u0441\u0441\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. \u041a\u0430\u043a \u044d\u0442\u043e \u0447\u0430\u0441\u0442\u043e \u0431\u044b\u0432\u0430\u0435\u0442, \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0435\u0441\u043b\u0438 \u0438 \u043f\u0438\u0441\u0430\u043b\u0438 \u0442\u0435\u0441\u0442\u044b, \u0442\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043c\u043e\u0434\u0443\u043b\u044c\u043d\u044b\u0435, \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u0438 end-to-end \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0449\u0438\u043a\u043e\u0432. \u0414\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f QA-\u0438\u043d\u0436\u0435\u043d\u0435\u0440\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 &#171;\u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u0441\u0442\u0435\u043d\u0434&#187;, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044b \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f (\u0435\u0449\u0435 \u043e\u043a\u043e\u043b\u043e 40, \u0441 \u043f\u043e\u0437\u0432\u043e\u043b\u0435\u043d\u0438\u044f \u0441\u043a\u0430\u0437\u0430\u0442\u044c, &#171;\u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432&#187;), \u0441\u0435\u0440\u0432\u0435\u0440 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 (\u0441 \u043d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u044f\u0441\u043d\u044b\u043c \u043d\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435\u043c \u044d\u0442\u043e\u0439 \u0441\u0430\u043c\u043e\u0439 \u0431\u0430\u0437\u044b), \u0431\u0440\u043e\u043a\u0435\u0440 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 (RabbitMQ) \u0438 \u0432\u0441\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435, \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041d\u0430 \u044d\u0442\u043e\u0442 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u0441\u0442\u0435\u043d\u0434 \u043d\u0430\u0442\u0440\u0430\u0432\u043b\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0448\u0430\u0442\u0430\u044e\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0437\u0430 \u0432\u0441\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u0441\u043d\u0430\u0440\u0443\u0436\u0438 \u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0435 \u0442\u043e\u0447\u043a\u0438, \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0411\u0414 \u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b UI \u043f\u044b\u0442\u0430\u044f\u0441\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u0432 \u0432 \u0433\u0440\u0430\u043d\u0438\u0446\u0430\u0445 (\u0438 \u0437\u0430 \u043d\u0438\u043c\u0438!) \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0445 \u0432\u0445\u043e\u0434\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\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-346259","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/346259","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=346259"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/346259\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=346259"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=346259"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=346259"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}