{"id":457681,"date":"2025-04-28T03:19:34","date_gmt":"2025-04-28T03:19:34","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=457681"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=457681","title":{"rendered":"<span>\u0418\u0441\u043a\u0443\u0441\u0441\u0442\u0432\u043e Unit-\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f: \u0441\u043e\u043a\u0440\u0430\u0449\u0430\u0435\u043c Arrange \u0434\u043e \u043d\u0443\u043b\u044f<\/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\"><a href=\"https:\/\/habr.com\/ru\/companies\/ruvds\/articles\/894522\/\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/fm\/ww\/6g\/fmww6gyfqght63nt1t6wxykpdaq.png\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/webt\/fm\/ww\/6g\/fmww6gyfqght63nt1t6wxykpdaq.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/webt\/fm\/ww\/6g\/fmww6gyfqght63nt1t6wxykpdaq.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/a><\/p>\n<p> Unit-\u0442\u0435\u0441\u0442\u044b \u043e\u0447\u0435\u043d\u044c \u0432\u0430\u0436\u043d\u043e \u0438 \u043d\u0443\u0436\u043d\u043e \u043f\u0438\u0441\u0430\u0442\u044c, \u043d\u043e \u0432\u043e\u0442 \u043d\u0435\u0437\u0430\u0434\u0430\u0447\u0430 \u2014 \u043d\u0430 \u043d\u0438\u0445 \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u0438! \u041f\u0440\u043e\u0447\u0438\u0442\u0430\u0432 \u044d\u0442\u0443 \u0441\u0442\u0430\u0442\u044c\u044e, \u0432\u044b \u0443\u0437\u043d\u0430\u0435\u0442\u0435 \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u043e \u043d\u043e\u0432\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u0438\u0445 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0442 \u043a\u0443\u0447\u0443 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0438 \u043d\u0435\u0440\u0432\u043e\u0432.<\/p>\n<p> \u042d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0435\u0437\u043d\u0430 .NET \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043a\u043e\u0433\u0434\u0430-\u043b\u0438\u0431\u043e \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u043b\u0438\u0441\u044c \u0441 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c unit \u0442\u0435\u0441\u0442\u043e\u0432, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0442\u0438\u043c \u0438 \u0442\u0435\u0445\u043b\u0438\u0434\u0430\u043c \u0432 \u043f\u043e\u0438\u0441\u043a\u0435 \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0439 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0438 \u0434\u043b\u044f \u0441\u0432\u043e\u0435\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b.<a name=\"habracut\"><\/a><\/p>\n<h2><font color=\"#3AC1EF\">\u041c\u043e\u0442\u0438\u0432\u0430\u0446\u0438\u044f<\/font><\/h2>\n<p> \u041a\u0442\u043e \u043f\u0438\u0448\u0435\u0442 \u044e\u043d\u0438\u0442 \u0442\u0435\u0441\u0442\u044b \u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u0435? \u041d\u0430\u0432\u0435\u0440\u043d\u043e\u0435, \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043b\u044e\u0431\u043e\u0439 \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u044c \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438.<br \/> \u041a\u043e\u043c\u0443 \u043d\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u0435 \u043f\u0440\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u044e\u043d\u0438\u0442 \u0442\u0435\u0441\u0442\u043e\u0432? \u041d\u0430\u0432\u0435\u0440\u043d\u043e\u0435, \u0442\u0430\u043a\u0436\u0435, \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u0432\u0441\u0435\u043c, \u043a\u0442\u043e \u0438\u0445 \u043f\u0438\u0448\u0435\u0442.<\/p>\n<p> \u042f \u043f\u043e\u043b\u0430\u0433\u0430\u044e, \u0447\u0442\u043e \u043d\u0438 \u0443 \u043a\u043e\u0433\u043e \u043d\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u0441\u043e\u043c\u043d\u0435\u043d\u0438\u0439 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u043f\u0438\u0441\u0430\u0442\u044c \u044e\u043d\u0438\u0442 \u0442\u0435\u0441\u0442\u044b.<\/p>\n<ul>\n<li>\u041f\u0438\u043b\u0438\u0448\u044c \u043d\u043e\u0432\u0443\u044e \u0444\u0438\u0447\u0443? \u041f\u0440\u043e\u0432\u0435\u0440\u044c \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0441\u0442\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438.<\/li>\n<li>\u0412\u044b\u044f\u0432\u0438\u043b\u0438 \u0431\u0430\u0433? \u041f\u043e\u043a\u0440\u043e\u0439\u0442\u0435 \u0442\u0435\u0441\u0442\u043e\u043c \u0444\u0438\u043a\u0441.<\/li>\n<li>\u0425\u043e\u0447\u0435\u0448\u044c \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0432 \u0441\u0442\u0430\u0440\u043e\u043c \u043a\u043e\u0434\u0435? \u0414\u0435\u0431\u0430\u0436\u044c \u0447\u0435\u0440\u0435\u0437 test runner.<\/li>\n<\/ul>\n<p> \u0421\u043a\u043e\u043b\u044c\u043a\u043e \u0418\u0418\u0448\u0435\u043a \u043d\u0435 \u043f\u0440\u0438\u0434\u0443\u043c\u0430\u044e\u0442, \u0430 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f \u043e\u0441\u0442\u0430\u043d\u0435\u0442\u0441\u044f \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u2014 \u0432 \u0441\u043f\u0440\u0438\u043d\u0442 \u043d\u0430\u043f\u0438\u0445\u0430\u043b\u0438 \u0431\u0438\u0437\u043d\u0435\u0441 \u0444\u0438\u0447, \u0430 \u0432\u0430\u0448 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0432\u043e\u0442 \u0442\u0430\u043a:<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/lt\/pd\/ws\/ltpdwsih83d5faye3ovf7z3igcg.png\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/webt\/lt\/pd\/ws\/ltpdwsih83d5faye3ovf7z3igcg.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/webt\/lt\/pd\/ws\/ltpdwsih83d5faye3ovf7z3igcg.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/div>\n<p> \u042d\u0442\u043e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u044f \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u043d\u043e \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0434\u0441\u0442\u0443\u043f\u0438\u0442\u044c\u0441\u044f \u043a \u0440\u0435\u0448\u0435\u043d\u0438\u044e, \u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c\u2026<\/p>\n<h2><font color=\"#3AC1EF\">\u041e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u044e\u043d\u0438\u0442 \u0442\u0435\u0441\u0442\u043e\u0432<\/font><\/h2>\n<p> \u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0438 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0440\u0430\u0437\u043d\u044b\u0435, \u043d\u043e \u0438\u0437 \u043c\u043e\u0435\u0439 \u043a\u043e\u043c\u043c\u0435\u0440\u0447\u0435\u0441\u043a\u043e\u0439 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0438 \u2014 \u0445\u043e\u0440\u043e\u0448\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c \u0434\u0432\u0430 \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u043f\u043e \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u043a\u043e\u0434\u0430.<\/p>\n<p> \u041a\u043e\u043d\u0435\u0447\u043d\u043e, \u0440\u0435\u0447\u044c \u0438\u0434\u0451\u0442 \u043f\u0440\u043e AAA \u0438 RoyOsherove.<\/p>\n<h3><font color=\"#3AC1EF\">\u258d \u041d\u0430 \u043f\u0430\u043b\u044c\u0446\u0430\u0445 \u043f\u0440\u043e AAA<\/font><\/h3>\n<p> \u041a\u0430\u043a \u0432\u044b \u043c\u043e\u0433\u043b\u0438 \u043f\u043e\u043d\u044f\u0442\u044c \u044d\u0442\u043e \u043d\u0435 \u043e \u0431\u0430\u0442\u0430\u0440\u0435\u0439\u043a\u0430\u0445 \u0438\u043b\u0438 \u0438\u0433\u0440\u0430\u0445, \u0430 \u043f\u0440\u043e \u044e\u043d\u0438\u0442-\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435.<br \/> \u0421\u043e\u0433\u043b\u0430\u0441\u0438\u0442\u0435\u0441\u044c, \u0432 \u0442\u0430\u043a\u043e\u043c \u0441\u043b\u043e\u0436\u043d\u043e\u043c \u043c\u0438\u0440\u0435, \u043a\u0430\u043a \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435, \u0441\u043b\u043e\u0436\u043d\u043e \u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f, \u043a\u043e\u0433\u0434\u0430 \u0432\u0441\u0451 \u043b\u0435\u0436\u0438\u0442 \u0433\u0434\u0435 \u043f\u043e\u043f\u0430\u043b\u043e, \u043d\u0435 \u043d\u0430 \u0441\u0432\u043e\u0438\u0445 \u043c\u0435\u0441\u0442\u0430\u0445. <\/p>\n<p> \u0413\u043e\u0440\u0430\u0437\u0434\u043e \u043f\u0440\u043e\u0449\u0435, \u043a\u043e\u0433\u0434\u0430 \u0432\u0441\u0451 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043e, \u043b\u0435\u0436\u0438\u0442, \u0442\u0430\u043a \u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u043f\u043e \u043f\u043e\u043b\u043e\u0447\u043a\u0430\u043c.<\/p>\n<p> \u041e\u0434\u043d\u0430\u0436\u0434\u044b \u0443\u043c\u043d\u044b\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u043f\u043e\u0434\u0443\u043c\u0430\u043b\u0438 \u0438 \u043f\u043e\u043d\u044f\u043b\u0438, \u0447\u0442\u043e \u0438 \u0442\u0435\u0441\u0442\u044b \u043c\u043e\u0436\u043d\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438 \u0440\u0430\u0437\u043b\u043e\u0436\u0438\u0442\u044c \u043d\u0430 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0435 \u0438 \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u0435 \u044d\u0442\u0430\u043f\u044b:<\/p>\n<ul>\n<li><b><font color=\"#3AC1EF\">Arrange<\/font><\/b>. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0435\u043a\u0446\u0438\u0438 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043a\u043e\u0434, \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0437\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u0442\u0435\u0441\u0442\u0430. \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432, \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445, \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043c\u043e\u043a\u043e\u0432 \u0438 \u0442\u0430\u043a \u0434\u0430\u043b\u0435\u0435.<\/li>\n<li><b><font color=\"#3AC1EF\">Act<\/font><\/b>. \u0417\u0430\u0442\u0435\u043c \u0438\u0434\u0451\u0442 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435. \u0422\u043e \u0435\u0441\u0442\u044c, \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432\u044b\u0437\u043e\u0432 \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u0433\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0430. <\/li>\n<li><b><font color=\"#3AC1EF\">Assert<\/font><\/b>. \u0424\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u044d\u0442\u0430\u043f \u2014 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430. \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f \u0432\u0441\u0451, \u0447\u0442\u043e \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c. \u041a\u0430\u043a\u0438\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438\u0441\u044c \u0434\u0430\u043d\u043d\u044b\u0435, \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432, \u0432\u044b\u0437\u0432\u0430\u043b\u043e\u0441\u044c \u043b\u0438 \u0442\u043e, \u0447\u0442\u043e \u043d\u0443\u0436\u043d\u043e, \u0431\u044b\u043b\u0430 \u043b\u0438 \u043e\u0448\u0438\u0431\u043a\u0430. \u0412 \u043e\u0431\u0449\u0435\u043c, \u0435\u0441\u0442\u044c \u0433\u0434\u0435 \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c\u0441\u044f.<\/li>\n<\/ul>\n<p> \u0412\u043e\u0442 \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u043f\u0430\u0442\u0442\u0435\u0440\u043d Arrange-Act-Assert \u0437\u0430 \u0441\u0447\u0451\u0442 \u0441\u0432\u043e\u0435\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u0438 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u0438 \u0432 \u043e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u0438 \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u043e\u0432 \u0441\u0442\u0430\u043b \u0434\u0435-\u0444\u0430\u043a\u0442\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043e\u043c \u0438\u043d\u0434\u0443\u0441\u0442\u0440\u0438\u0438.<\/p>\n<h3><font color=\"#3AC1EF\">\u258d \u041d\u0430 \u043f\u0430\u043b\u044c\u0446\u0430\u0445 \u043f\u0440\u043e Roy Osherove<\/font><\/h3>\n<p> \u0415\u0441\u0442\u044c \u0438 \u0434\u0440\u0443\u0433\u043e\u0439 \u0434\u0435-\u0444\u0430\u043a\u0442\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442 \u0438\u043d\u0434\u0443\u0441\u0442\u0440\u0438\u0438 \u043f\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e, \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u0441\u0442\u043e\u044f\u0432\u0448\u0438\u0439\u0441\u044f \u043d\u0430 99,9%.<\/p>\n<p> \u042d\u0442\u043e \u043a\u043e\u043d\u0432\u0435\u043d\u0446\u0438\u044f \u043f\u043e \u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u044e \u0442\u0435\u0441\u0442\u043e\u0432 Roy Osherove, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \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=\"plaintext\">UnitOfWork_StateUnderTest_ExpectedBehavior <\/code><\/pre>\n<p> \u041b\u044e\u0434\u044f\u043c, \u0432\u043b\u0430\u0434\u0435\u044e\u0449\u0438\u043c \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u0438\u043c \u044f\u0437\u044b\u043a\u043e\u043c, \u0432 \u0446\u0435\u043b\u043e\u043c \u0443\u0436\u0435 \u0432\u0441\u0451 \u043f\u043e\u043d\u044f\u0442\u043d\u043e.<br \/> \u0422\u043e \u0435\u0441\u0442\u044c \u0432 \u0438\u043c\u0435\u043d\u0438 \u0442\u0435\u0441\u0442\u0430 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c:<\/p>\n<ul>\n<li>\u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u0443\u044e \u0435\u0434\u0438\u043d\u0438\u0446\u0443 \u0440\u0430\u0431\u043e\u0442\u044b,<\/li>\n<li>\u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c\u043e\u0435 \u0432 \u0442\u0435\u0441\u0442\u0435,<\/li>\n<li>\u043e\u0436\u0438\u0434\u0430\u0435\u043c\u043e\u0435 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435.<\/li>\n<\/ul>\n<p> \u0427\u0443\u0432\u0441\u0442\u0432\u0443\u0435\u0442\u0435, \u043d\u0430 \u0447\u0442\u043e \u043f\u043e\u0445\u043e\u0436\u0435? \u0415\u0441\u043b\u0438 \u0432\u044b \u043f\u043e\u0434\u0443\u043c\u0430\u043b\u0438 \u043f\u0440\u043e AAA, \u0442\u043e \u0441\u0443\u0442\u044c \u0442\u043e\u0447\u043d\u043e \u0443\u043b\u043e\u0432\u0438\u043b\u0438.<\/p>\n<p> \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0440\u043d\u043e\u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u043e\u0447\u0435\u043d\u044c \u043b\u0451\u0433\u043a\u043e\u0435 \u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u043a\u0440\u0430\u0442\u043d\u043e \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u0442 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438 \u043b\u0451\u0433\u043a\u043e\u0441\u0442\u044c \u0432 \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438.<\/p>\n<h3><font color=\"#3AC1EF\">\u258d \u041f\u0440\u0438\u043c\u0435\u0440<\/font><\/h3>\n<p> <\/p>\n<pre><code class=\"cs\">public record Adder(int Value) {     public Adder Add(Adder that) =&gt;         new(Value + that.Value); }  public class AdderTests {     [Fact]     public void Add_AddingToZero_ResultNotAffectedByZero()     {         \/\/ arrange         Adder ten = new(10);         Adder zero = new(0);              \/\/ act         var sum = ten.Add(zero);              \/\/ assert         sum.Should().Be(ten);     } } <\/code><\/pre>\n<p> <\/p>\n<h2><font color=\"#3AC1EF\">\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430\u0442\u0438\u043a\u0430<\/font><\/h2>\n<p> \u041f\u043e\u0447\u0435\u043c\u0443 \u043e\u0431 \u044d\u0442\u0438\u0445 \u0441\u043e\u0433\u043b\u0430\u0448\u0435\u043d\u0438\u044f\u0445 \u0431\u044b\u043b\u043e \u0432\u0430\u0436\u043d\u043e \u0441\u043a\u0430\u0437\u0430\u0442\u044c? \u0414\u0435\u043b\u043e \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043a \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u0438 \u0437\u0430\u0442\u0435\u043c \u044f\u0432\u043d\u043e \u0438 \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u043e \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0443\u0437\u043a\u0438\u0435 \u043c\u0435\u0441\u0442\u0430.<\/p>\n<p> \u041f\u043e \u0441\u0443\u0442\u0438, \u043f\u0440\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u0442\u0435\u0441\u0442\u043e\u0432 \u0443\u0437\u043a\u043e\u0435 \u043c\u0435\u0441\u0442\u043e \u043e\u0434\u043d\u043e \u2014 \u044d\u0442\u043e Arrange \u044d\u0442\u0430\u043f, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 Act \u0438 Assert \u0432 \u0441\u0440\u0435\u0434\u043d\u0435\u043c \u0437\u0430\u043d\u0438\u043c\u0430\u044e\u0442 2 \u0441\u0442\u0440\u043e\u0447\u043a\u0438. \u0410 \u0432\u043e\u0442 Arrange \u0441\u0430\u043c\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0439 \u0438 <b><font color=\"#3AC1EF\">\u043e\u0431\u044a\u0451\u043c\u043d\u044b\u0439<\/font><\/b>. \u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432, \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0439, \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0439, \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0439 \u2014 \u0432\u0441\u0451 \u0442\u0430\u043c.<\/p>\n<p> \u0410 \u0442\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u043c, \u0447\u0442\u043e \u043c\u044b \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0442\u0438\u043f\u043e\u0432\u0443\u044e \u0442\u0430\u0441\u043a\u0443 \u0432 \u043a\u0440\u043e\u0432\u0430\u0432\u043e\u043c \u044b\u043d\u0442\u044d\u0440\u043f\u0440\u0430\u0439\u0437\u0435.<br \/> \u0422\u043e\u0433\u0434\u0430 \u043c\u044b \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043d\u0435\u043a\u0438\u0439 \u0443\u0441\u0440\u0435\u0434\u043d\u0451\u043d\u043d\u044b\u0439 \u0442\u0438\u043f\u043e\u0432\u043e\u0439 \u043a\u043e\u0434 \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0443\u0441\u0440\u0435\u0434\u043d\u0451\u043d\u043d\u044b\u0439\u2026<\/p>\n<h3><font color=\"#3AC1EF\">\u258d \u0422\u0438\u043f\u043e\u0432\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a<\/font><\/h3>\n<p> <\/p>\n<pre><code class=\"cs\">public class SomeHandler(     ISomeRepository repository,     ISomeProcessingService service,     ISomeSessionAccessor sessionAccessor,     ISomeExternalDataProvider provider,     IOptions&lt;SomeOptions&gt; options,     ILogger&lt;SomeHandler&gt; logger) {     private readonly SomeOptions _options = options.Value;      public async Task&lt;SomeResponse&gt; Handle(SomeRequest request, CancellationToken ct)     {         if (request.Field1 &lt; 0)             throw new SomeException();          var entity = await repository.GetByField2(request.Field2, ct);         if (request.Field3)         {             await service.ProcessAsync(entity, ct);             logger.LogInformation(\"processed\");         }          var session = sessionAccessor.Session;         session.ChangeStatus();          var externalData = await Task.WhenAll(             _options.Sources.Select(                 source =&gt; provider.GetCollectionBySource(source, ct)));         return new SomeResponse(             entity,             externalData.SelectMany(x =&gt; x).ToArray());     } } <\/code><\/pre>\n<p> \u042d\u0442\u043e \u0442\u0430\u043a\u043e\u0439 \u0441\u0440\u0435\u0434\u043d\u0435\u043d\u044c\u043a\u0438\u0439 JSON \u043f\u0435\u0440\u0435\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0442\u0435\u043b\u044c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0447\u0442\u043e-\u0442\u043e \u0442\u0430\u043c \u0441\u0434\u0435\u043b\u0430\u043b \u0432 \u0441\u0435\u0441\u0441\u0438\u0438, \u0447\u0442\u043e-\u0442\u043e \u0437\u0430\u043b\u043e\u0433\u0433\u0438\u0440\u043e\u0432\u0430\u043b \u0438 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u043b \u0438\u0437 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438, \u0430 \u043f\u043e\u0442\u043e\u043c \u0447\u0442\u043e-\u0442\u043e \u043f\u043e\u043b\u043e\u0436\u0438\u043b \u0432 \u0431\u0430\u0437\u0443 \u0438 \u0447\u0442\u043e-\u0442\u043e \u043e\u0442\u0434\u0430\u043b \u043d\u0430\u0440\u0443\u0436\u0443.<\/p>\n<p> \u0411\u0435\u0441\u0441\u043c\u044b\u0441\u043b\u0435\u043d\u043d\u044b\u0439 \u0438 \u0431\u0435\u0441\u043f\u043e\u0449\u0430\u0434\u043d\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432, \u043f\u0443\u0441\u043a\u0430\u0439 \u0441\u0435\u043c\u0430\u043d\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0438 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u0435\u0440\u043d\u044b\u0439.<\/p>\n<p> \u0410 \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0447\u043d\u0451\u043c \u043f\u0438\u0441\u0430\u0442\u044c \u044e\u043d\u0438\u0442 \u0442\u0435\u0441\u0442 \u0441\u043e\u0433\u043b\u0430\u0441\u043d\u043e \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0430\u043c \u041b\u043e\u043d\u0434\u043e\u043d\u0441\u043a\u043e\u0439 \u0448\u043a\u043e\u043b\u044b \u0438 \u0443\u0432\u0438\u0434\u0438\u043c, \u0447\u0442\u043e \u043e\u043d \u043d\u0435 \u0432\u043b\u0435\u0437\u0430\u0435\u0442 \u0432 \u043e\u0434\u0438\u043d \u0441\u043b\u0430\u0439\u0434 PowerPoint \u043f\u0440\u0435\u0437\u0435\u043d\u0442\u0430\u0446\u0438\u0438.<\/p>\n<p> \u0414\u043b\u044f \u043c\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 NSubstitute \u2014 <a href=\"https:\/\/www.nuget.org\/packages\/NSubstitute\">www.nuget.org\/packages\/NSubstitute<\/a> <br \/> \u041f\u0440\u0435\u0434\u043f\u043e\u0447\u0438\u0442\u0430\u044e \u0435\u0451 \u0437\u0430 \u043b\u0430\u043a\u043e\u043d\u0438\u0447\u043d\u043e\u0441\u0442\u044c \u0438 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 <a href=\"https:\/\/www.securitylab.ru\/news\/540800.php\">SponsorLink \u0438\u043d\u0446\u0438\u0434\u0435\u043d\u0442\u043e\u0432<\/a>.<\/p>\n<pre><code class=\"cs\">public class SomeHandlerTests {     [Fact]     public async Task Handle_HappyPath_DoesNotThrow()     {         var repository = Substitute.For&lt;ISomeRepository&gt;();         repository.GetByField2(default, default)             .ReturnsForAnyArgs(new SomeEntity(                 Field2: nameof(SomeEntity.Field2),                 Data: nameof(SomeEntity.Data)));          var service = Substitute.For&lt;ISomeProcessingService&gt;();          var sessionAccessor = Substitute.For&lt;ISomeSessionAccessor&gt;();         sessionAccessor.Session.Returns(Substitute.For&lt;ISession&gt;());          var provider = Substitute.For&lt;ISomeExternalDataProvider&gt;();         provider.GetCollectionBySource(default, default)             .ReturnsForAnyArgs([                 new SomeExternalData(Guid.NewGuid(), Content: 1.ToString(), [1, 2, 3]),                 new SomeExternalData(Guid.NewGuid(), Content: 2.ToString(), [4, 5, 6]),             ]);          var handler = new SomeHandler(             repository,             service,             sessionAccessor,             provider,             Options.Create(new SomeOptions { Sources = [\"source1\", \"source2\"] }),             NullLogger&lt;SomeHandler&gt;.Instance);          var response = await handler.Handle(new SomeRequest(                 Field1: 123,                 Field2: \"123\",                 Field3: true),             ct: default);          Assert.NotNull(response);     } } <\/code><\/pre>\n<p> \u0418 \u044d\u0442\u043e \u0432\u0441\u0451 \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439 HappyPath.<\/p>\n<p> \u0410 \u0435\u0441\u0442\u044c \u0435\u0449\u0451 \u0432\u0435\u0442\u0432\u043b\u0435\u043d\u0438\u044f, \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u044f, \u043e\u0448\u0438\u0431\u043a\u0438 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0439 \u0438 \u043c\u043d\u043e\u0433\u043e\u0435 \u0434\u0440\u0443\u0433\u043e\u0435.<br \/> \u041a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0431\u044b, \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u043d\u0435\u0441\u0442\u0438 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0443 SUT (system under test) \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u0442\u0435\u0441\u0442\u0435.<\/p>\n<p> \u041d\u043e \u0432\u0435\u0434\u044c \u0432 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0435\u0441\u0442\u044c \u0434\u0440\u0443\u0433\u0438\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u044b, \u0438 \u0442\u043e\u0433\u0434\u0430 \u043a\u043e\u0434 \u043f\u0440\u043e\u0434\u0443\u0431\u043b\u0438\u0440\u0443\u0435\u0442\u0441\u044f, \u0430 \u0431\u043e\u0439\u043b\u0435\u0440\u043f\u043b\u0435\u0439\u0442 \u0440\u0430\u0437\u0440\u0430\u0441\u0442\u0451\u0442\u0441\u044f \u043d\u0435 \u043c\u0435\u043d\u044c\u0448\u0435, \u0447\u0435\u043c \u0441 \u043b\u0438\u043d\u0435\u0439\u043d\u043e\u0439 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c\u044e.<\/p>\n<h3><font color=\"#3AC1EF\">\u258d \u0427\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c?<\/font><\/h3>\n<p> \u041f\u043e \u0441\u0443\u0442\u0438 Arrange \u044d\u0442\u0430\u043f \u043f\u0440\u0435\u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043f\u0440\u043e\u0441\u0442\u0443\u044e \u0446\u0435\u043b\u044c \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0438 \u0442\u0435\u0441\u0442\u0430.<\/p>\n<p> \u0414\u043b\u044f \u0435\u0451 \u0434\u043e\u0441\u0442\u0438\u0436\u0435\u043d\u0438\u044f \u0448\u0430\u0431\u043b\u043e\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u0433\u043e\u0442\u043e\u0432\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435, \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043d\u0443\u0436\u043d\u044b\u0439 \u043a\u0435\u0439\u0441 \u0434\u043b\u044f \u043f\u0440\u043e\u0433\u043e\u043d\u0430.<\/p>\n<p> \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f, \u043e\u0442\u0432\u0435\u0442 \u043d\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0441\u0430\u043c \u0441\u043e\u0431\u043e\u0439:<\/p>\n<ul>\n<li>\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0433\u043e\u0442\u043e\u0432\u043a\u0443 \u0434\u0430\u043d\u043d\u044b\u0445. \u0423\u0431\u0440\u0430\u0442\u044c \u043f\u043e \u043c\u0430\u043a\u0441\u0438\u043c\u0443\u043c\u0443 \u0432\u0441\u0435 \u0432\u044b\u0437\u043e\u0432\u044b <code>new()<\/code> \u0438 <code>[]<\/code>.<\/li>\n<li>\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0433\u043e\u0442\u043e\u0432\u043a\u0443 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u044f. \u0423\u0431\u0440\u0430\u0442\u044c \u043f\u043e \u043c\u0430\u043a\u0441\u0438\u043c\u0443\u043c\u0443 \u0432\u0441\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043c\u043e\u043a\u043e\u0432.<\/li>\n<\/ul>\n<p> <\/p>\n<h2><font color=\"#3AC1EF\">\u0420\u0435\u0448\u0435\u043d\u0438\u0435<\/font><\/h2>\n<p> \u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043f\u043e\u043d\u044f\u0442\u044c \u00ab\u043a\u0430\u043a \u0434\u0435\u043b\u0430\u0442\u044c\u00bb, \u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u043c\u0441\u044f \u0441 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u043c\u043e\u0433\u0443\u0442 \u043d\u0430\u043c \u0440\u0435\u0448\u0438\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u0441\u0432\u043e\u0435\u0439 \u0441\u0438\u043d\u0435\u0440\u0433\u0438\u0435\u0439. \u042d\u0442\u043e \u0440\u044f\u0434 NuGet \u043f\u0430\u043a\u0435\u0442\u043e\u0432, \u043e \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0432\u044b \u043c\u043e\u0433\u043b\u0438 \u0438\u043b\u0438 \u043d\u0435 \u043c\u043e\u0433\u043b\u0438 \u0440\u0430\u043d\u0435\u0435 \u0437\u043d\u0430\u0442\u044c. \u0418 \u043f\u0435\u0440\u0432\u044b\u0439 \u0438\u0437 \u043d\u0438\u0445\u2026<\/p>\n<h3><font color=\"#3AC1EF\">\u258d AutoFixture<\/font><\/h3>\n<p> <a href=\"https:\/\/www.nuget.org\/packages\/AutoFixture\">www.nuget.org\/packages\/AutoFixture<\/a> <\/p>\n<p> \u042d\u0442\u043e\u0442 NuGet \u043f\u0430\u043a\u0435\u0442 \u0443\u043c\u0435\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u044b \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0434\u043b\u044f \u0442\u0438\u043f\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445, \u043e\u0431\u043b\u0430\u0434\u0430\u044e\u0449\u0438\u0445 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430\u043c\u0438:<\/p>\n<pre><code class=\"cs\">var fixture = new Fixture(); var bar = fixture.Create&lt;Bar&gt;();  record Foo(Guid Id); record Bar(     Foo Foo,     string Name,     bool IsBaz,     int Number); <\/code><\/pre>\n<p> \u0421\u043e\u0437\u0434\u0430\u0442\u0435\u043b\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u2014 Mark Seemann, \u0430\u0432\u0442\u043e\u0440 \u043a\u043d\u0438\u0433\u0438 Dependency Injection in .NET.<\/p>\n<p> \u041e\u043d\u0430 \u0440\u0435\u0448\u0430\u0435\u0442 \u0440\u043e\u0432\u043d\u043e \u0442\u0443 \u0437\u0430\u0434\u0430\u0447\u0443, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u044b \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u043b\u0438: \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0431\u0435\u0441\u0441\u043c\u044b\u0441\u043b\u0435\u043d\u043d\u043e\u0435 \u0434\u0442\u043e \u043d\u0430 300 \u043f\u043e\u043b\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u043b\u043e\u0436\u0438\u0442\u044c \u0432 \u0431\u0430\u0437\u0443, \u0438 \u0432\u043c\u0435\u0441\u0442\u043e \u0440\u0443\u0447\u043d\u043e\u0439 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u044b\u0437\u043e\u0432 \u0432 \u043e\u0434\u043d\u0443 \u0441\u0442\u0440\u043e\u0447\u043a\u0443.<\/p>\n<p> \u041a\u043e\u0434 \u0432\u044b\u0448\u0435 \u0441\u043e\u0437\u0434\u0430\u0441\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043e\u0431\u044a\u0435\u043a\u0442:<\/p>\n<pre><code class=\"json\">{   \"Foo\": {     \"Id\": \"537478f7-a6f0-4e85-8ca2-1d7e0da97e7e\"   },   \"Name\": \"Name0e4afc29-8ef7-4991-aaa1-2294a456cccc\",   \"IsBaz\": false,   \"Number\": 58 } <\/code><\/pre>\n<p> <\/p>\n<h3><font color=\"#3AC1EF\">\u258d AutoData<\/font><\/h3>\n<p> <a href=\"https:\/\/www.nuget.org\/packages\/AutoFixture.Xunit2\/5.0.0-preview0011\">www.nuget.org\/packages\/AutoFixture.Xunit2\/5.0.0-preview0011<\/a> <\/p>\n<p> \u041d\u043e \u044f \u2014 \u043b\u0435\u043d\u0438\u0432\u044b\u0439 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u0430\u043a \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442, \u043c\u043d\u0435 \u043d\u0435 \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u0438\u043d\u0441\u0442\u0430\u043d\u0446\u0438\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u044b <code>Fixture<\/code> \u0438 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b. \u041c\u043d\u0435 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b, \u0447\u0442\u043e\u0431\u044b \u0432\u0441\u0451 \u0431\u044b\u043b\u043e \u0433\u043e\u0442\u043e\u0432\u043e, \u043a\u043e\u0433\u0434\u0430 \u0443\u0436\u0435 \u0437\u0430\u043f\u0443\u0449\u0435\u043d \u0442\u0435\u0441\u0442.<\/p>\n<p> \u041a \u0441\u0447\u0430\u0441\u0442\u044c\u044e, \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0442 \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440\u044b AutoFixture \u043a \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u043c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430\u043c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, xUnit.<br \/> \u041d\u0435\u0444\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e \u044f \u0438\u0445 \u043d\u0430\u0437\u044b\u0432\u0430\u044e AutoData \u043f\u043e \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0443, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0443\u0435\u0442 \u043d\u0443\u0436\u043d\u044b\u0439 \u043c\u043d\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b.<\/p>\n<p> \u042d\u0442\u0438\u043c \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u043c \u043c\u044b \u0440\u0430\u0437\u043c\u0435\u0447\u0430\u0435\u043c \u0442\u0435\u0441\u0442\u044b-\u0442\u0435\u043e\u0440\u0438\u0438, \u0438 \u043d\u0435\u044f\u0432\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 <code>Fixture<\/code> \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u043e\u0431\u044a\u0435\u043a\u0442\u044b, \u0437\u0430\u043f\u0440\u043e\u0448\u0435\u043d\u043d\u044b\u0435 \u0432 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u0445 \u0442\u0435\u043e\u0440\u0438\u0438.<\/p>\n<pre><code class=\"cs\">public class TestClass {     [Theory, AutoData]     public void TestMethod1(string foo)     {         foo.Should().NotBeEmpty();     }        [Theory, AutoData]     public void TestMethod2(Foo foo)     {         foo.Bar.Should().NotBeEmpty();     } }  public class Foo {     public string Bar { get; set; } } <\/code><\/pre>\n<p> <\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/eu\/9q\/94\/eu9q94dfre6t9fod6_r2lengsig.png\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/webt\/eu\/9q\/94\/eu9q94dfre6t9fod6_r2lengsig.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/webt\/eu\/9q\/94\/eu9q94dfre6t9fod6_r2lengsig.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/div>\n<p> \u041d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435, \u044d\u0442\u043e \u0441\u0438\u043d\u0442\u0435\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0442\u0435\u043e\u0440\u0438\u044f, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043a\u0435\u0439\u0441 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d.<br \/> \u041d\u043e \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0440\u0438 \u043d\u0430\u043b\u0438\u0447\u0438\u0438 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445?<\/p>\n<p> \u0415\u0441\u0442\u044c \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b <code>InlineAutoData<\/code>, <code>MemberAutoData<\/code>, <code>ClassAutoData<\/code> \u0438 \u0442\u0430\u043a \u0434\u0430\u043b\u0435\u0435:<\/p>\n<pre><code class=\"cs\">public class TestClass {     [Theory]     [MemberAutoData(nameof(TestData))]     public void TestMethod3(int a, int b, int c)     {         c.Should().BeGreaterThan(a + b);     }      public static IEnumerable&lt;object[]&gt; TestData =     [         [-1, -2],         [-3, -4]     ]; } <\/code><\/pre>\n<p> <\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/lr\/zb\/db\/lrzbdb34jinp3gli2vuni3cqefi.png\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/webt\/lr\/zb\/db\/lrzbdb34jinp3gli2vuni3cqefi.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/webt\/lr\/zb\/db\/lrzbdb34jinp3gli2vuni3cqefi.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/div>\n<p> \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u043b \u0434\u043b\u044f \u043a\u0435\u0439\u0441\u0430 \u043f\u0435\u0440\u0432\u044b\u0435 \u0434\u0432\u0430 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 \u0442\u0435\u0441\u0442\u0430, \u0430 \u0442\u0440\u0435\u0442\u0438\u0439 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u043b\u0441\u044f \u0441\u0438\u043b\u0430\u043c\u0438 AutoFixture. \u041e\u0433\u043d\u0435\u043d\u043d\u0430\u044f \u0448\u0442\u0443\u043a\u0430, \u043e\u0431\u043c\u0430\u0437\u044b\u0432\u0430\u0435\u043c\u0441\u044f Success&#8217;\u043e\u043c!<\/p>\n<p> \u0418\u0442\u043e\u0433\u043e, \u043c\u044b \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u0433\u043e\u0442\u043e\u0432\u043a\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0433\u043e\u0442\u043e\u0432\u044b \u0434\u0432\u0438\u0433\u0430\u0442\u044c\u0441\u044f \u0434\u0430\u043b\u044c\u0448\u0435!<\/p>\n<h3><font color=\"#3AC1EF\">\u258d AutoData + \u043c\u043e\u043a\u0438 == AutoNSubstitute<\/font><\/h3>\n<p> \u0414\u0430\u0432\u0430\u0439\u0442\u0435, \u043f\u043e\u0434\u0443\u043c\u0430\u0435\u043c: \u0447\u0442\u043e \u043d\u0430\u043c \u0434\u0435\u043b\u0430\u0442\u044c \u0441 \u043c\u043e\u043a\u0430\u043c\u0438?<br \/> \u041f\u043e \u0441\u0443\u0442\u0438, \u043f\u0440\u0438 \u0433\u043e\u0442\u043e\u0432\u043a\u0435 \u043c\u043e\u043a\u043e\u0432 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u043c\u043e\u043a\u0430, \u0430 \u0437\u0430\u0442\u0435\u043c \u0441\u0435\u0442\u0430\u043f\u0438\u043c \u043a\u0430\u043a\u043e\u0439-\u043d\u0438\u0431\u0443\u0434\u044c \u0432\u043e\u0437\u0432\u0440\u0430\u0442 \u043b\u0438\u0431\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u043c, \u043b\u0438\u0431\u043e \u0434\u0440\u0443\u0433\u0438\u043c \u043c\u043e\u043a\u043e\u043c.<\/p>\n<p> \u0412\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u0432\u043e\u043f\u0440\u043e\u0441: \u0430 \u0447\u0442\u043e \u0435\u0441\u043b\u0438 \u043f\u043e\u043f\u0440\u043e\u0441\u0438\u0442\u044c AutoFixture \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043c\u043e\u043a, \u0432 \u0432\u043e\u0437\u0432\u0440\u0430\u0442\u044b \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0431\u044b\u043b\u0438 \u0431\u044b \u0437\u0430\u043f\u0438\u0441\u0430\u043d\u044b \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0432\u044b\u0437\u043e\u0432\u043e\u0432 <code>Create<\/code>?<\/p>\n<p> \u041e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f, \u0442\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0430\u0446\u0438\u0438 <a href=\"https:\/\/www.nuget.org\/packages\/AutoFixture.AutoNSubstitute\/\">AutoNSubstitute<\/a>.<\/p>\n<p> \u0422\u0430\u043a\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0442 NuGet \u043f\u0430\u043a\u0435\u0442\u044b \u0434\u043b\u044f Moq, RhinoMocks \u0438 FakeItEasy.<\/p>\n<p> \u0427\u0442\u043e\u0431\u044b \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043c\u043e\u043a\u0438, \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u043a\u0430\u0447\u0430\u0442\u044c \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u0435\u0442\u043e\u0434\u0430 Customize, \u043f\u0440\u0438\u043c\u0435\u0440 \u0442\u0435\u0441\u0442\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<pre><code class=\"cs\">public class TestClassClass {     [Fact]     public async Task Test()     {         var fixture = new Fixture()             .Customize(                 new AutoNSubstituteCustomization                 {                     ConfigureMembers = true                 });         var provider = fixture.Create&lt;ISomeExternalDataProvider&gt;();         var collection = await provider.GetCollectionBySource(             source: fixture.Create&lt;string&gt;(),             ct: default);         Assert.NotEmpty(collection);     } } <\/code><\/pre>\n<p> <\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/20\/oe\/u0\/20oeu0i6stepcundme2-vt5vuf4.png\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/webt\/20\/oe\/u0\/20oeu0i6stepcundme2-vt5vuf4.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/webt\/20\/oe\/u0\/20oeu0i6stepcundme2-vt5vuf4.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/div>\n<p> \u041d\u0430 \u0441\u043a\u0440\u0438\u043d\u0435 \u0432\u0438\u0434\u043d\u043e \u0432 \u043e\u0442\u043b\u0430\u0434\u043a\u0435, \u0447\u0442\u043e \u0432\u0435\u0440\u043d\u0443\u043b \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 <code>ISomeExternalDataProvider<\/code>, \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 AutoFixture, \u043f\u0440\u0438 \u0432\u044b\u0437\u043e\u0432\u0435 \u043c\u0435\u0442\u043e\u0434\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u044b\u043b \u0437\u0430\u043c\u043e\u043a\u0430\u043d \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438.<\/p>\n<h3><font color=\"#3AC1EF\">\u258d \u0421\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u0432\u0441\u0451 \u0432\u043c\u0435\u0441\u0442\u0435<\/font><\/h3>\n<p> \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u0432\u0441\u0435 \u044d\u0442\u0438 \u0442\u0440\u0438 \u0432\u0435\u0449\u0438 \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0432\u043e\u0435\u0434\u0438\u043d\u043e \u0447\u0435\u0440\u0435\u0437 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0430\u0442\u0440\u0438\u0431\u0443\u0442.<\/p>\n<p> \u0412 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u043c\u0435\u0442\u043e\u0434, \u0440\u0430\u0437\u043c\u0435\u0447\u0435\u043d\u043d\u044b\u0439 \u0442\u0430\u043a\u0438\u043c \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u043c, \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u044c \u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u044b, \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0435 \u043c\u043e\u043a\u0438:<\/p>\n<pre><code class=\"cs\">public class AutoNSubstituteDataAttribute() :     AutoDataAttribute(         () =&gt; new Fixture().Customize(             new AutoNSubstituteCustomization             {                 ConfigureMembers = true             })); <\/code><\/pre>\n<p> \u0418\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438 \u0442\u0430\u043a\u043e\u0433\u043e \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430 \u043d\u0435\u0442. \u041a\u0441\u0442\u0430\u0442\u0438, \u041c\u0430\u0440\u043a \u0421\u0438\u043c\u0430\u043d\u043d \u0432 \u0441\u0432\u043e\u0451\u043c \u0431\u043b\u043e\u0433\u0435 \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0435\u0433\u043e \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043c\u043e\u0434\u0435\u043b\u044c \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f \u0447\u0435\u0440\u0435\u0437 \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435.<\/p>\n<p> \u0418 \u0442\u0435\u043f\u0435\u0440\u044c, \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u0432 \u043d\u0430\u0448 \u0442\u0438\u043f\u043e\u0432\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a, \u0442\u043e\u0442 \u0442\u0435\u0441\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435 \u043f\u043e\u043c\u0435\u0449\u0430\u043b\u0441\u044f \u043d\u0438 \u0432 \u043a\u0430\u043a\u0438\u0435 \u044d\u043a\u0440\u0430\u043d\u044b, \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u0442\u044c \u0432 2 \u0441\u0442\u0440\u043e\u0447\u043a\u0438 \u0438, \u0430\u0431\u0441\u0442\u0440\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0432\u0448\u0438\u0441\u044c \u043e\u0442 \u0440\u0443\u0442\u0438\u043d\u044b, \u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0438\u0442\u044c\u0441\u044f \u043d\u0430 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u044f\u0445 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043b\u043e\u0433\u0438\u043a\u0438:<\/p>\n<pre><code class=\"cs\">public class SomeHandlerTests2 {     [Theory, AutoNSubstituteData]     public async Task Handle_HappyPath_DoesNotThrow(         SomeRequest request,         SomeHandler handler)     {         var response = await handler.Handle(request, ct: default);          Assert.NotNull(response);     }          [Theory, AutoNSubstituteData]     public async Task Handle_Field1LessThanZero_ThrowsSomeException(         SomeRequest request,         SomeHandler handler)     {         await Assert.ThrowsAsync&lt;SomeException&gt;(             () =&gt; handler.Handle(request with { Field1 = -1 }, ct: default));     }          [Theory, AutoNSubstituteData]     public async Task Handle_NoExternalData_ItIsEmptyInResponse(         SomeRequest request,         [Frozen] ISomeExternalDataProvider provider,         SomeHandler handler)     {         provider.GetCollectionBySource(default, default)             .ReturnsForAnyArgs([]);         var response = await handler.Handle(request, ct: default);         response.ExternalDataCollection.Should().BeEmpty();     } } <\/code><\/pre>\n<p> <\/p>\n<h3><font color=\"#3AC1EF\">\u258d \u041f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0435 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0438<\/font><\/h3>\n<p> AutoFixture \u2014 \u0431\u0435\u0437 \u0441\u043e\u043c\u043d\u0435\u043d\u0438\u044f \u043c\u043e\u0449\u043d\u044b\u0439 \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440 \u0434\u0430\u043d\u043d\u044b\u0445, \u043d\u043e \u043d\u0435 \u0432\u0441\u0435\u0441\u0438\u043b\u044c\u043d\u044b\u0439. \u041e\u043d \u043d\u0435 \u0443\u043c\u0435\u0435\u0442 \u0447\u0438\u0442\u0430\u0442\u044c \u043c\u044b\u0441\u043b\u0438, \u0438 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e \u0436\u0435\u043b\u0430\u043d\u0438\u044e. \u0415\u043c\u0443 \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u043e\u0431\u0449\u0438\u0442\u044c, \u043a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u044d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c.<\/p>\n<p> \u041f\u043e\u044d\u0442\u043e\u043c\u0443, \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u0432\u0435\u0440\u043d\u0443\u0442\u044c\u0441\u044f \u043a \u0432\u043e\u043f\u0440\u043e\u0441\u0443 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u044f. \u041e\u0434\u043d\u0430\u043a\u043e, \u043f\u0440\u0438\u0432\u0435\u0434\u0451\u043d\u043d\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f \u0447\u0435\u0440\u0435\u0437 \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u0443\u0434\u0430\u0447\u043d\u0430\u044f, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0432 \u043e\u0434\u043d\u043e\u0439 \u043a\u043e\u0434\u043e\u0432\u043e\u0439 \u0431\u0430\u0437\u0435 \u043c\u043e\u0433\u0443\u0442 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0440\u0430\u0437\u043d\u044b\u0435 \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043d\u044b\u0435 \u043e\u0431\u043b\u0430\u0441\u0442\u0438, \u0440\u0430\u0437\u043d\u044b\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438, \u0447\u0442\u043e \u043f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043a \u0432\u0437\u0440\u044b\u0432\u0443 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u0432-\u043d\u0430\u0441\u043b\u0435\u0434\u043d\u0438\u043a\u043e\u0432, \u0438 \u0432 \u043d\u0438\u0445 \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043b\u0435\u0433\u043a\u043e \u0437\u0430\u043f\u0443\u0442\u0430\u0442\u044c\u0441\u044f.<\/p>\n<p> \u041c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u0434\u0443\u043c\u0430\u0442\u044c \u0434\u0440\u0443\u0433\u043e\u0439 \u043f\u0443\u0442\u044c \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u044f, \u0438 \u0441\u0435\u0439\u0447\u0430\u0441 \u044f \u043f\u043e\u043a\u0430\u0436\u0443 \u044d\u0442\u043e \u043d\u0430 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0438\u0437 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0438. \u0414\u043e\u043f\u0443\u0441\u0442\u0438\u043c, \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0439 Value Object, \u043c\u043e\u0434\u0435\u043b\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u0434\u0438\u0441\u043a\u0440\u0435\u0442\u043d\u0443\u044e \u043e\u0446\u0435\u043d\u043a\u0443 \u043e\u0442 1 \u0434\u043e 5:<\/p>\n<pre><code class=\"cs\">public struct Rate {     public Rate(byte value)     {         if (value is &gt;= 1 and &lt;= 5)             Value = value;         else throw new ArgumentOutOfRangeException(             nameof(value),             value,              message: \"rate can be from 1 to 5\");     }      public byte Value { get; } } <\/code><\/pre>\n<p> \u0422\u043e\u0433\u0434\u0430, \u0435\u0441\u043b\u0438 \u043c\u044b \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0438\u0442\u044c \u0432 \u0442\u0435\u0441\u0442\u0435 \u043e\u0431\u044a\u0435\u043a\u0442 \u043e\u0446\u0435\u043d\u043a\u0438, \u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u043e\u0448\u0438\u0431\u043a\u0443:<\/p>\n<pre><code class=\"cs\">public class TestClassClass {     [Theory, AutoData]     public void Test22(Rate rate)     {         rate.Value.Should().NotBe(0);     } } <\/code><\/pre>\n<p> <\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/f4\/38\/qf\/f438qfw9kggps7_kbiu38aiap-u.png\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/webt\/f4\/38\/qf\/f438qfw9kggps7_kbiu38aiap-u.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/webt\/f4\/38\/qf\/f438qfw9kggps7_kbiu38aiap-u.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/div>\n<p> \u0414\u0435\u043b\u043e \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e AutoFixture \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e-\u0441\u0432\u043e\u0435\u043c\u0443:<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/lw\/ol\/we\/lwolwehtfp8zgjb5ncwhzeg8baa.png\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/webt\/lw\/ol\/we\/lwolwehtfp8zgjb5ncwhzeg8baa.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/webt\/lw\/ol\/we\/lwolwehtfp8zgjb5ncwhzeg8baa.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/div>\n<p> <\/p>\n<h3><font color=\"#3AC1EF\">\u258d \u041e\u0431\u043e\u0431\u0449\u0451\u043d\u043d\u044b\u0435 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b + static abstract<\/font><\/h3>\n<p> \u041f\u0440\u043e\u0432\u0435\u0434\u0451\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 research. \u0415\u0441\u043b\u0438 \u043c\u044b \u0437\u0430\u0433\u043b\u044f\u043d\u0435\u043c \u0432\u043d\u0443\u0442\u0440\u044c \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430 <code>[AutoData]<\/code>, \u0442\u043e \u0443\u0432\u0438\u0434\u0438\u043c, \u0447\u0442\u043e \u0443 \u043d\u0435\u0433\u043e \u0435\u0441\u0442\u044c \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0436\u0438\u0434\u0430\u0435\u0442 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 \u0434\u0435\u043b\u0435\u0433\u0430\u0442 \u0442\u0438\u043f\u0430 <code>Func&lt;Fixture&gt;<\/code>:<\/p>\n<pre><code class=\"cs\">public AutoDataAttribute()     : this(() =&gt; new Fixture()) { } <\/code><\/pre>\n<p> \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f, \u043c\u043e\u0436\u043d\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u044d\u0442\u0438\u043c \u0438 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442 Fixture \u043b\u044e\u0431\u044b\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u043c \u043d\u0430\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c. \u041e\u0434\u043d\u0430\u043a\u043e \u043a\u0430\u043a \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u044b \u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0432 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u043c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430? \u0422\u0430\u043a \u0435\u0449\u0451 \u0438 \u0432 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430 \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u044b \u0434\u0430 \u0442\u0438\u043f\u044b\u2026<\/p>\n<p> \u0412 \u044d\u0442\u043e\u043c \u043d\u0430\u043c \u043f\u043e\u043c\u043e\u0433\u0443\u0442 \u043d\u043e\u0432\u043e\u0432\u0432\u0435\u0434\u0435\u043d\u0438\u044f C# 11: <code>static abstract<\/code> \u0438 \u043e\u0431\u043e\u0431\u0449\u0451\u043d\u043d\u044b\u0435 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435, \u043a\u0430\u043a \u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f, \u0445\u043e\u0440\u043e\u0448\u043e \u0432\u043c\u0435\u0441\u0442\u0435 \u0441\u043e\u0447\u0435\u0442\u0430\u044e\u0442\u0441\u044f.<\/p>\n<pre><code class=\"cs\">public interface IFixtureCustomizer {     static abstract void Customize(IFixture fixture); }  public class AutoDataAttribute&lt;TFixtureCustomizer&gt; : AutoDataAttribute     where TFixtureCustomizer : IFixtureCustomizer {     public AutoDataAttribute() : base(         fixtureFactory: () =&gt;         {             var fixture = new Fixture();             TFixtureCustomizer.Customize(fixture);             return fixture;         })     {     } } <\/code><\/pre>\n<p> \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0448\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438 \u043e\u0446\u0435\u043d\u043e\u043a \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<pre><code class=\"cs\">public class RateGenerator : IFixtureCustomizer {     public static void Customize(IFixture fixture) =&gt;         fixture.Register(() =&gt; new Rate((byte)Random.Shared.Next(1, 6))); }  public class TestClassClass {     [Theory, AutoData&lt;RateGenerator&gt;]     public void Test22(Rate rate)     {         rate.Value.Should().NotBe(0);     } } <\/code><\/pre>\n<p> \u0415\u0441\u043b\u0438 \u043d\u0430 \u0432\u0430\u0448\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0434\u043e \u0441\u0438\u0445 \u043f\u043e\u0440 .NET 6 \u0438 \u0441\u0442\u0430\u0440\u0448\u0435, \u0442\u043e \u0432\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u043c\u043e\u0436\u0435\u0442\u0435 \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043f\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c\u0443 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0443:<\/p>\n<ul>\n<li>\u0414\u0435\u043b\u0430\u0435\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 <code>IFixtureCustomizer<\/code> \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u043d\u044b\u043c.<\/li>\n<li>\u0412 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0438 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430 \u043e\u0436\u0438\u0434\u0430\u0435\u043c \u0442\u0438\u043f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u0447\u0435\u0440\u0435\u0437 <code>typeof<\/code>.<\/li>\n<li>\u0412\u043d\u0443\u0442\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0430\u0442\u043e\u0440\u0430 \u0440\u0435\u0444\u043b\u0435\u043a\u0441\u0438\u0435\u0439 \u0447\u0435\u0440\u0435\u0437 <code>Activator.CreateInstance<\/code>.<\/li>\n<\/ul>\n<p> <\/p>\n<h3><font color=\"#3AC1EF\">\u258d \u0422\u0438\u043f\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432<\/font><\/h3>\n<p> \u0422\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0436\u0435\u043b\u0430\u0435\u043c\u043e\u0435 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0438 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0447\u0435\u0440\u0435\u0437 \u043a\u043b\u0430\u0441\u0441\u044b, \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0431\u0443\u0434\u0443\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u0447\u0435\u0440\u0435\u0437 AutoData \u0432 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u0445 \u0442\u0435\u043e\u0440\u0438\u0438.<\/p>\n<p> \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, AutoFixture \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 <a href=\"https:\/\/www.nuget.org\/packages\/Fare\">\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 Fare \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0441\u0442\u0440\u043e\u043a \u043f\u043e \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u043c\u0443 \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e\u043c\u0443 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044e. <\/a><\/p>\n<p> \u041c\u043d\u0435 \u044d\u0442\u043e \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u043b\u043e\u0441\u044c \u043d\u0435\u0434\u0430\u0432\u043d\u043e \u0432 \u043f\u0435\u0442 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u2014 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0430 \u043c\u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0441\u0442\u0440\u043e\u043a \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u043e\u0439 \u043b\u0435\u043a\u0441\u0438\u043a\u0438. \u0412\u043e\u043e\u0440\u0443\u0436\u0438\u0432\u0448\u0438\u0441\u044c \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0435\u0439 \u0438 \u0441\u043c\u0435\u043a\u0430\u043b\u043a\u043e\u0439, \u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043b \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0443 \u0441\u043f\u0438\u0441\u043a\u0430 \u0442\u0430\u043a\u0438\u0445 \u0441\u0442\u0440\u043e\u043a \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043b\u0430\u0441\u0441\u0430, \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0435\u043c\u043e\u0433\u043e \u0432 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0442\u0435\u0441\u0442\u0430:<\/p>\n<pre><code class=\"cs\">public record LexerInput([property:MinLength(10), MaxLength(25)] TokenInput[] TokenInputs) : IReadOnlyList&lt;string&gt; {     public IEnumerator&lt;string&gt; GetEnumerator() =&gt;         TokenInputs.Select(x =&gt; x.Value).GetEnumerator();      IEnumerator IEnumerable.GetEnumerator() =&gt; GetEnumerator();      public int Count =&gt; TokenInputs.Length;      public string this[int index] =&gt; TokenInputs[index].Value;      public override string ToString() =&gt;         TokenInputs.Aggregate(             TokenInput.AdditiveIdentity,             (x, y) =&gt; x + y).Value; }  public record TokenInput([property: RegularExpression(TokenInput.Pattern)] string Value) :     IAdditiveIdentity&lt;TokenInput, TokenInput&gt;,     IAdditionOperators&lt;TokenInput, TokenInput, TokenInput&gt; {     [StringSyntax(StringSyntaxAttribute.Regex)]     public const string Pattern = \"[a-zA-Z]+|[0-9]+|[+]{2}\";      public static TokenInput operator +(TokenInput left, TokenInput right) =&gt;         new(left.Value + \" \" + right.Value);      public static TokenInput AdditiveIdentity { get; } = new(string.Empty); } <\/code><\/pre>\n<p> AutoFixture \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0430 \u0438\u043c\u0451\u043d <code>System.ComponentModel.DataAnnotations<\/code> \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u043f\u0440\u0430\u0432\u0438\u043b \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p> \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0438\u0437 <code>[RegularExpression]<\/code> \u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u043f\u0430\u0442\u0442\u0435\u0440\u043d, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u043f\u0440\u043e\u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0440\u0430\u0437\u043c\u0435\u0447\u0435\u043d\u043d\u043e\u0435 \u0441\u0442\u0440\u043e\u043a\u043e\u0432\u043e\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e, \u0430 \u0438\u0437 <code>[MinLength]<\/code> \u0438 <code>[MaxLength]<\/code> \u0447\u0438\u0442\u0430\u044e\u0442\u0441\u044f \u0433\u0440\u0430\u043d\u0438\u0446\u044b \u043e\u0442\u0440\u0435\u0437\u043a\u0430 \u0434\u043b\u044f \u0432\u044b\u0431\u043e\u0440\u0430 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u043c\u0430\u0441\u0441\u0438\u0432\u0430.<br \/> \u0412 \u0442\u0435\u0441\u0442\u0435 \u044d\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432\u043e\u0442 \u0442\u0430\u043a:<\/p>\n<pre><code class=\"cs\">public class RegexLexerTests(ITestOutputHelper output) {     [Theory, AutoHydraScriptData]     public void GetTokens_MockedRegex_ValidOutput(         LexerInput input,         [Frozen] IStructure structure,         RegexLexer lexer)     {         output.WriteLine(input.ToString());         var patterns = TokenInput.Pattern.Split('|');          structure.Regex.ReturnsForAnyArgs(             new Regex(string.Join('|', patterns.Select((x, i) =&gt; $\"(?&lt;TYPE{i}&gt;{x})\"))));         var tokenTypes = Enumerable.Range(0, patterns.Length)             .Select(x =&gt; new TokenType($\"TYPE{x}\"))             .ToList();          \/\/ ReSharper disable once GenericEnumeratorNotDisposed         structure.GetEnumerator()             .ReturnsForAnyArgs(_ =&gt; tokenTypes.GetEnumerator());          var tokens = lexer.GetTokens(input.ToString());         for (var i = 0; i &lt; input.Count; i++)         {             output.WriteLine(tokens[i].ToString());             tokens[i].Value.Should().BeEquivalentTo(input[i]);             tokens[i].Type.Should().BeOneOf(tokenTypes);         }     } } <\/code><\/pre>\n<p> <\/p>\n<h2><font color=\"#3AC1EF\">\u0418\u0442\u043e\u0433\u0438<\/font><\/h2>\n<p> \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u0432\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u043f\u043e\u0448\u0430\u0433\u043e\u0432\u0443\u044e \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044e \u043f\u043e \u0440\u0430\u043a\u0435\u0442\u043d\u043e\u043c\u0443 \u0442\u043e\u0440\u043f\u0435\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u044e\u043d\u0438\u0442 \u0442\u0435\u0441\u0442\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0434\u0432\u0443\u0445\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043d\u043e\u0439 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 Arrange \u044d\u0442\u0430\u043f\u0430:<\/p>\n<ul>\n<li>\u0413\u043e\u0442\u043e\u0432\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 = AutoFixture + AutoData.<\/li>\n<li>\u0413\u043e\u0442\u043e\u0432\u043a\u0430 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u044f = AutoFixture + AutoData + \u043c\u043e\u043a\u0438.<\/li>\n<\/ul>\n<p> \u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u043d\u043e\u0432\u043e\u0432\u0432\u0435\u0434\u0435\u043d\u0438\u044f\u043c C# \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0442\u044c \u0442\u0438\u043f\u043e\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e, \u044d\u043b\u0435\u0433\u0430\u043d\u0442\u043d\u043e \u0438 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e. \u041d\u0443 \u0438, \u0432 \u043a\u043e\u043d\u0446\u0435 \u043a\u043e\u043d\u0446\u043e\u0432, \u043d\u0430 \u0434\u0436\u0430\u0432\u0435 \u0442\u0430\u043a \u043d\u0435 \u0441\u0434\u0435\u043b\u0430\u0435\u0448\u044c!<\/p>\n<p> <b><font color=\"#3AC1EF\">\u042d\u0442\u0443 \u043c\u0435\u0442\u043e\u0434\u0438\u043a\u0443 \u0443\u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0435 C# \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u044f\u0445: \u041c\u0422\u0421, Chibbis \u0438 \u041f\u0421\u0411. \u0410 \u043c\u043e\u0438 \u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a\u0438 \u0438\u0437 Mindbox \u043d\u0430\u0447\u0430\u043b\u0438 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f.<\/font><\/b><\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/zu\/zv\/81\/zuzv812lhrcwe39nfbrwzpsjdqs.png\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/webt\/zu\/zv\/81\/zuzv812lhrcwe39nfbrwzpsjdqs.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/webt\/zu\/zv\/81\/zuzv812lhrcwe39nfbrwzpsjdqs.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/div>\n<p> \u0415\u0449\u0451 \u044f \u0432\u0435\u0434\u0443 Telegram-\u043a\u0430\u043d\u0430\u043b <a href=\"https:\/\/t.me\/+MgLRLb8ZSVAxNTY6\">StepOne<\/a>, \u043a\u0443\u0434\u0430 \u0432\u044b\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u044e \u043c\u043d\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430 \u043f\u0440\u043e \u043a\u043e\u043c\u043c\u0435\u0440\u0447\u0435\u0441\u043a\u0443\u044e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043d\u0430 C#, \u0434\u0430\u044e \u043a\u0430\u0440\u044c\u0435\u0440\u043d\u044b\u0435 \u0441\u043e\u0432\u0435\u0442\u044b, \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u044e \u0438\u0441\u0442\u043e\u0440\u0438\u0438 \u0438\u0437 \u043b\u0438\u0447\u043d\u043e\u0433\u043e \u043e\u043f\u044b\u0442\u0430 \u0438 \u0440\u0430\u0441\u043a\u0440\u044b\u0432\u0430\u044e \u0432\u0441\u0435 \u0442\u0430\u0439\u043d\u044b IT-\u0438\u043d\u0434\u0443\u0441\u0442\u0440\u0438\u0438.<\/p>\n<p> \u00a9 2025 \u041e\u041e\u041e \u00ab\u041c\u0422 \u0424\u0418\u041d\u0410\u041d\u0421\u00bb<\/p>\n<blockquote><p><b><font color=\"#3AC1EF\"><a href=\"https:\/\/t.me\/ruvds_community\">Telegram-\u043a\u0430\u043d\u0430\u043b \u0441\u043e \u0441\u043a\u0438\u0434\u043a\u0430\u043c\u0438, \u0440\u043e\u0437\u044b\u0433\u0440\u044b\u0448\u0430\u043c\u0438 \u043f\u0440\u0438\u0437\u043e\u0432 \u0438 \u043d\u043e\u0432\u043e\u0441\u0442\u044f\u043c\u0438 IT \ud83d\udcbb<\/a><\/font><\/b><\/p><\/blockquote>\n<p><a href=\"https:\/\/ruvds.com\/ru-rub?utm_source=habr&amp;utm_medium=article&amp;utm_campaign=Stefanio%0A&amp;utm_content=iskusstvo_unit_testirovaniya_sokrashhaem_arrange_do_nulya\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/yo\/se\/km\/yosekm4h_f7y7oia-ghbbpc0phi.png\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/webt\/yo\/se\/km\/yosekm4h_f7y7oia-ghbbpc0phi.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/webt\/yo\/se\/km\/yosekm4h_f7y7oia-ghbbpc0phi.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/a><\/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\/894522\/\"> https:\/\/habr.com\/ru\/articles\/894522\/<\/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\"><a href=\"https:\/\/habr.com\/ru\/companies\/ruvds\/articles\/894522\/\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/fm\/ww\/6g\/fmww6gyfqght63nt1t6wxykpdaq.png\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/webt\/fm\/ww\/6g\/fmww6gyfqght63nt1t6wxykpdaq.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/webt\/fm\/ww\/6g\/fmww6gyfqght63nt1t6wxykpdaq.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/a><\/p>\n<p> Unit-\u0442\u0435\u0441\u0442\u044b \u043e\u0447\u0435\u043d\u044c \u0432\u0430\u0436\u043d\u043e \u0438 \u043d\u0443\u0436\u043d\u043e \u043f\u0438\u0441\u0430\u0442\u044c, \u043d\u043e \u0432\u043e\u0442 \u043d\u0435\u0437\u0430\u0434\u0430\u0447\u0430 \u2014 \u043d\u0430 \u043d\u0438\u0445 \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u0438! \u041f\u0440\u043e\u0447\u0438\u0442\u0430\u0432 \u044d\u0442\u0443 \u0441\u0442\u0430\u0442\u044c\u044e, \u0432\u044b \u0443\u0437\u043d\u0430\u0435\u0442\u0435 \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u043e \u043d\u043e\u0432\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u0438\u0445 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0442 \u043a\u0443\u0447\u0443 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0438 \u043d\u0435\u0440\u0432\u043e\u0432.<\/p>\n<p> \u042d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0435\u0437\u043d\u0430 .NET \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043a\u043e\u0433\u0434\u0430-\u043b\u0438\u0431\u043e \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u043b\u0438\u0441\u044c \u0441 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c unit \u0442\u0435\u0441\u0442\u043e\u0432, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0442\u0438\u043c \u0438 \u0442\u0435\u0445\u043b\u0438\u0434\u0430\u043c \u0432 \u043f\u043e\u0438\u0441\u043a\u0435 \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0439 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0438 \u0434\u043b\u044f \u0441\u0432\u043e\u0435\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b.<\/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-457681","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/457681","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=457681"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/457681\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=457681"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=457681"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=457681"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}