{"id":276857,"date":"2016-03-24T11:30:03","date_gmt":"2016-03-24T08:30:03","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=276857"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=276857","title":{"rendered":"\u041f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0435 Android \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0448\u0430\u0433 \u0437\u0430 \u0448\u0430\u0433\u043e\u043c, \u0447\u0430\u0441\u0442\u044c \u0442\u0440\u0435\u0442\u044c\u044f"},"content":{"rendered":"<p>       <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/ddd\/981\/4fe\/ddd9814fe65645ffaa655874a6fd9dc0.jpg\"\/><\/p>\n<p>  \u0412 <a href=\"https:\/\/habrahabr.ru\/company\/rambler-co\/blog\/275943\/\">\u043f\u0435\u0440\u0432\u043e\u0439<\/a> \u0438 <a href=\"https:\/\/habrahabr.ru\/company\/rambler-co\/blog\/277343\/\">\u0432\u0442\u043e\u0440\u043e\u0439 \u0447\u0430\u0441\u0442\u044f\u0445<\/a> \u0441\u0442\u0430\u0442\u044c\u0438 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u043b\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 Github, \u0432\u043d\u0435\u0434\u0440\u0438\u043b\u0438 Dagger 2 \u0438 \u043f\u043e\u043a\u0440\u044b\u043b\u0438 \u043a\u043e\u0434 unit \u0442\u0435\u0441\u0442\u0430\u043c\u0438. \u0412 \u0437\u0430\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u0442\u0435\u0441\u0442\u044b, \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0442\u0435\u0445\u043d\u0438\u043a\u0443 TDD \u0438 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0441 \u0435\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435\u043c \u043d\u043e\u0432\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u0434\u0441\u043a\u0430\u0436\u0435\u043c, \u0447\u0442\u043e \u0447\u0438\u0442\u0430\u0442\u044c \u0434\u0430\u043b\u044c\u0448\u0435. <br \/>  <a name=\"habracut\"><\/a>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041f\u043e\u043b\u043d\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435<\/b><\/p>\n<div class=\"spoiler_text\">\n<ul>\n<li><a href=\"https:\/\/habrahabr.ru\/company\/rambler-co\/blog\/275943\/#1\">\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/a><\/li>\n<li><a href=\"https:\/\/habrahabr.ru\/company\/rambler-co\/blog\/275943\/#2\">\u0428\u0430\u0433 1. \u041f\u0440\u043e\u0441\u0442\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430<\/a><\/li>\n<li><a href=\"https:\/\/habrahabr.ru\/company\/rambler-co\/blog\/275943\/#9\">\u0428\u0430\u0433 2. \u0423\u0441\u043b\u043e\u0436\u043d\u0435\u043d\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430<\/a><\/li>\n<li><a href=\"https:\/\/habrahabr.ru\/company\/rambler-co\/blog\/277343\/#21\">\u0428\u0430\u0433 3. Dependency Injection<\/a><\/li>\n<li><a href=\"https:\/\/habrahabr.ru\/company\/rambler-co\/blog\/277343\/#26\">\u0428\u0430\u0433 4. \u041c\u043e\u0434\u0443\u043b\u044c\u043d\u043e\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/a><\/li>\n<li><a href=\"https:\/\/habrahabr.ru\/company\/rambler-co\/blog\/279799\/#31\">\u0428\u0430\u0433 5. \u0418\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<\/a><\/li>\n<li><a href=\"https:\/\/habrahabr.ru\/company\/rambler-co\/blog\/279799\/#32\">\u0428\u0430\u0433 6. \u0424\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/a><\/li>\n<li><a href=\"https:\/\/habrahabr.ru\/company\/rambler-co\/blog\/279799\/#33\">\u0428\u0430\u0433 7. TDD<\/a><\/li>\n<li><a href=\"https:\/\/habrahabr.ru\/company\/rambler-co\/blog\/279799\/#34\">\u0428\u0430\u0433 8. \u0427\u0442\u043e \u0434\u0430\u043b\u044c\u0448\u0435?<\/a><\/li>\n<li><a href=\"https:\/\/habrahabr.ru\/company\/rambler-co\/blog\/279799\/#35\">\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/a><\/li>\n<\/ul>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<h4>\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/h4>\n<p>  \u0412 \u043f\u0435\u0440\u0432\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0441\u0442\u0430\u0442\u044c\u0438 \u043c\u044b \u0432 \u0434\u0432\u0430 \u044d\u0442\u0430\u043f\u0430 \u0441\u043e\u0437\u0434\u0430\u043b\u0438 \u043f\u0440\u043e\u0441\u0442\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 github. \u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0431\u044b\u043b\u0430 \u0440\u0430\u0437\u0431\u0438\u0442\u0430 \u043d\u0430 \u0434\u0432\u0435 \u0447\u0430\u0441\u0442\u0438: \u043f\u0440\u043e\u0441\u0442\u0443\u044e \u0438 \u0441\u043b\u043e\u0436\u043d\u0443\u044e. \u0412\u043e \u0432\u0442\u043e\u0440\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u0432\u043d\u0435\u0434\u0440\u0438\u043b\u0438 Dagger 2 \u0438 \u043f\u043e\u043a\u0440\u044b\u043b\u0438 \u043a\u043e\u0434 unit \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Robolectric, Mockito, MockWebServer \u0438 JaCoCo.<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u0423\u0441\u043b\u043e\u0432\u043d\u0430\u044f \u0441\u0445\u0435\u043c\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/b><\/p>\n<div class=\"spoiler_text\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/e08\/de8\/101\/e08de8101f3b486b9c7f556126dea55e.png\"\/>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u0414\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u043a\u043b\u0430\u0441\u0441\u043e\u0432<\/b><\/p>\n<div class=\"spoiler_text\"><a href=\"https:\/\/habrastorage.org\/files\/4e0\/9f7\/802\/4e09f78028274958819a59445c3065fd.png\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/4e0\/9f7\/802\/4e09f78028274958819a59445c3065fd.png\"\/><\/a>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041f\u043e\u043a\u0440\u044b\u0442\u0438\u0435 \u0442\u0435\u0441\u0442\u0430\u043c\u0438<\/b><\/p>\n<div class=\"spoiler_text\"><a href=\"https:\/\/habrastorage.org\/files\/1c5\/86b\/69a\/1c586b69aa204d818e39e5ba22920b33.PNG\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/1c5\/86b\/69a\/1c586b69aa204d818e39e5ba22920b33.PNG\"\/><\/a>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u0421\u0445\u0435\u043c\u0430 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432<\/b><\/p>\n<div class=\"spoiler_text\"><a href=\"https:\/\/habrastorage.org\/files\/1c5\/86b\/69a\/da6d2cca88424fc2a7aa930a3de2cc8b.PNG\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/da6\/d2c\/ca8\/da6d2cca88424fc2a7aa930a3de2cc8b.png\"\/><\/a>  <\/div>\n<\/div>\n<p>  \u0412\u0441\u0435 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0439\u0442\u0438 \u043d\u0430 <a href=\"https:\/\/github.com\/andrey7mel\/android-step-by-step\">Github.<\/a><\/p>\n<p>  <a name=\"31\"><\/a><\/p>\n<h4>\u0428\u0430\u0433 5. \u0418\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<\/h4>\n<p>  <a href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%98%D0%BD%D1%82%D0%B5%D0%B3%D1%80%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%BD%D0%BE%D0%B5_%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5\">\u0418\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 (Integration testing) <\/a> \u2014 \u043e\u0434\u043d\u0430 \u0438\u0437 \u0444\u0430\u0437 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e\u0433\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f, \u043f\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u044b\u0435 \u043c\u043e\u0434\u0443\u043b\u0438 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u044e\u0442\u0441\u044f \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0432 \u0433\u0440\u0443\u043f\u043f\u0435.<br \/>  \u0412\u044b\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f 3 \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u043a \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u043c\u0443 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e:<\/p>\n<p>  <b>\u0421\u043d\u0438\u0437\u0443 \u0432\u0432\u0435\u0440\u0445 (Bottom Up Integration)<\/b><br \/>  \u0412\u0441\u0435 \u043d\u0438\u0437\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u0435 \u043c\u043e\u0434\u0443\u043b\u0438, \u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440\u044b \u0438\u043b\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0441\u043e\u0431\u0438\u0440\u0430\u044e\u0442\u0441\u044f \u0432\u043e\u0435\u0434\u0438\u043d\u043e \u0438 \u0437\u0430\u0442\u0435\u043c \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u044e\u0442\u0441\u044f. \u041f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u043c\u043e\u0434\u0443\u043b\u0435\u0439 \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0434\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. \u0414\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u043c, \u0435\u0441\u043b\u0438 \u0432\u0441\u0435 \u0438\u043b\u0438 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u0441\u0435 \u043c\u043e\u0434\u0443\u043b\u0438, \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c\u043e\u0433\u043e \u0443\u0440\u043e\u0432\u043d\u044f, \u0433\u043e\u0442\u043e\u0432\u044b. \u0422\u0430\u043a\u0436\u0435 \u0434\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u043e\u043c\u043e\u0433\u0430\u0435\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043f\u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430\u043c \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u0433\u043e\u0442\u043e\u0432\u043d\u043e\u0441\u0442\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. <\/p>\n<p>  <b>\u0421\u0432\u0435\u0440\u0445\u0443 \u0432\u043d\u0438\u0437 (Top Down Integration)<\/b><br \/>  \u0412\u043d\u0430\u0447\u0430\u043b\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0432\u0441\u0435 \u0432\u044b\u0441\u043e\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u0435 \u043c\u043e\u0434\u0443\u043b\u0438, \u0438 \u043f\u043e\u0441\u0442\u0435\u043f\u0435\u043d\u043d\u043e \u043e\u0434\u0438\u043d \u0437\u0430 \u0434\u0440\u0443\u0433\u0438\u043c \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043d\u0438\u0437\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u0435. \u0412\u0441\u0435 \u043c\u043e\u0434\u0443\u043b\u0438 \u0431\u043e\u043b\u0435\u0435 \u043d\u0438\u0437\u043a\u043e\u0433\u043e \u0443\u0440\u043e\u0432\u043d\u044f \u0441\u0438\u043c\u0443\u043b\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0437\u0430\u0433\u043b\u0443\u0448\u043a\u0430\u043c\u0438 \u0441 \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u044e, \u0437\u0430\u0442\u0435\u043c \u043f\u043e \u043c\u0435\u0440\u0435 \u0433\u043e\u0442\u043e\u0432\u043d\u043e\u0441\u0442\u0438 \u043e\u043d\u0438 \u0437\u0430\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u043c\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u043c\u0438. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043c\u044b \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u043c \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u0432\u0435\u0440\u0445\u0443 \u0432\u043d\u0438\u0437.<\/p>\n<p>  <b>\u0411\u043e\u043b\u044c\u0448\u043e\u0439 \u0432\u0437\u0440\u044b\u0432 (\u00abBig Bang\u00bb Integration)<\/b><br \/>  \u0412\u0441\u0435 \u0438\u043b\u0438 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u0441\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u044b\u0435 \u043c\u043e\u0434\u0443\u043b\u0438 \u0441\u043e\u0431\u0438\u0440\u0430\u044e\u0442\u0441\u044f \u0432\u043c\u0435\u0441\u0442\u0435 \u0432 \u0432\u0438\u0434\u0435 \u0437\u0430\u043a\u043e\u043d\u0447\u0435\u043d\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0438\u043b\u0438 \u0435\u0435 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438, \u0438 \u0437\u0430\u0442\u0435\u043c \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u0442\u0441\u044f \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. \u0422\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043e\u0447\u0435\u043d\u044c \u0445\u043e\u0440\u043e\u0448 \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0432\u0440\u0435\u043c\u0435\u043d\u0438.<\/p>\n<p>  \u0422\u0430\u043a \u043a\u0430\u043a \u0443 \u043d\u0430\u0441 \u0432\u0441\u0435 \u043c\u043e\u0434\u0443\u043b\u0438 \u0443\u0436\u0435 \u0433\u043e\u0442\u043e\u0432\u044b, \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434\u0445\u043e\u0434 <b>\u0441\u043d\u0438\u0437\u0443 \u0432\u0432\u0435\u0440\u0445<\/b>. <\/p>\n<h5>\u0418\u0442\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434<\/h5>\n<p>  \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u0442\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434, \u0442.\u0435 \u0431\u0443\u0434\u0435\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u043c\u043e\u0434\u0443\u043b\u0438 \u043e\u0434\u0438\u043d \u0437\u0430 \u043e\u0434\u043d\u0438\u043c, \u0441\u043d\u0438\u0437\u0443 \u0432\u0432\u0435\u0440\u0445. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0441\u0432\u044f\u0437\u043a\u0443 api + model, \u043f\u043e\u0442\u043e\u043c api + model + mapper + presenter, \u0437\u0430\u0442\u0435\u043c \u043e\u0431\u0449\u0443\u044e \u0441\u0432\u044f\u0437\u043a\u0443 api + model mapper + presenter + view<\/p>\n<h5>\u041d\u0435\u0433\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u0438 \u043f\u043e\u0437\u0438\u0442\u0438\u0432\u043d\u044b\u0439 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439<\/h5>\n<p>  \u0414\u043b\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c 2 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u044f \u043e\u0442\u0432\u0435\u0442\u0430 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430: \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u043e\u0442\u0432\u0435\u0442 \u0438 \u043e\u0448\u0438\u0431\u043a\u0430. \u0412 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u044d\u0442\u043e\u0433\u043e \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432. \u041f\u0435\u0440\u0435\u0434 \u043a\u0430\u0436\u0434\u044b\u043c \u0442\u0435\u0441\u0442\u043e\u043c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0442\u044c \u043e\u0442\u0432\u0435\u0442 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 (MockWebServer) \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b. <\/p>\n<p>  \u0421\u0445\u0435\u043c\u0430 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430 (api + model): <\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/ba1\/a99\/92b\/ba1a9992b45b4b4381233fa613cc7650.png\"\/><\/p>\n<p>  \u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430 (api + model), \u043c\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043c\u043e\u0434\u0443\u043b\u044f Retrfofit \u0438 ModelImpl: <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">@Test public void testGetRepoList() {     TestSubscriber&lt;List&lt;RepositoryDTO&gt;&gt; testSubscriber = new TestSubscriber&lt;&gt;();    model.getRepoList(TestConst.TEST_OWNER).subscribe(testSubscriber);     testSubscriber.assertNoErrors();    testSubscriber.assertValueCount(1);     List&lt;RepositoryDTO&gt; actual = testSubscriber.getOnNextEvents().get(0);     assertEquals(7, actual.size());    assertEquals(&quot;Android-Rate&quot;, actual.get(0).getName());    assertEquals(&quot;andrey7mel\/Android-Rate&quot;, actual.get(0).getFullName());    assertEquals(26314692, actual.get(0).getId()); }<\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0421\u0445\u0435\u043c\u0430 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430 (api + model + mapper + presenter): <\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/2b6\/3f8\/ffb\/2b63f8ffb2734ed4bbf231088fcb71ee.png\"\/><\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430 (api + model + mapper + presenter)<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">@Test public void testLoadData() {    repoInfoPresenter.onCreateView(null);    repoInfoPresenter.onStop();      verify(mockView).showBranches(branchList);    verify(mockView).showContributors(contributorList); }  @Test public void testLoadDataWithError() {    setErrorAnswerWebServer();     repoInfoPresenter.onCreateView(null);    repoInfoPresenter.onStop();     verify(mockView, times(2)).showError(TestConst.ERROR_RESPONSE_500); }<\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0412 \u0438\u0442\u043e\u0433\u0435 \u0443 \u043d\u0430\u0441 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f \u043f\u043e\u043b\u043d\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0432\u0441\u0435\u0445 \u043c\u043e\u0434\u0443\u043b\u0435\u0439 \u0434\u0440\u0443\u0433 \u0441 \u0434\u0440\u0443\u0433\u043e\u043c, \u0441\u043d\u0438\u0437\u0443 \u0432\u0432\u0435\u0440\u0445. \u0415\u0441\u043b\u0438 \u0433\u0434\u0435 \u0442\u043e \u043c\u043e\u0434\u0443\u043b\u0438 \u0431\u0443\u0434\u0443\u0442 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e, \u043c\u044b \u0431\u044b\u0441\u0442\u0440\u043e \u0443\u0432\u0438\u0434\u0438\u043c \u044d\u0442\u043e \u043f\u043e \u0442\u0435\u0441\u0442\u0430\u043c.<\/p>\n<p>  <a name=\"32\"><\/a><\/p>\n<h4>\u0428\u0430\u0433 6. \u0424\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/h4>\n<p>  <a href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%A4%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%BE%D0%BD%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5\">\u0424\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/a> \u2014 \u044d\u0442\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u041f\u041e \u0432 \u0446\u0435\u043b\u044f\u0445 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c\u043e\u0441\u0442\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0445 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439, \u0442\u043e \u0435\u0441\u0442\u044c \u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u0438 \u041f\u041e \u0432 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u0445 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u0445 \u0440\u0435\u0448\u0430\u0442\u044c \u0437\u0430\u0434\u0430\u0447\u0438, \u043d\u0443\u0436\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c. \u0424\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0442, \u0447\u0442\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u041f\u041e, \u043a\u0430\u043a\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u043e\u043d\u043e \u0440\u0435\u0448\u0430\u0435\u0442.<\/p>\n<p>  \u0412 \u0440\u0430\u043c\u043a\u0430\u0445 \u043d\u0430\u0448\u0435\u0433\u043e Android \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0441\u0442\u0430\u0432\u0438\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0443\u044e \u043a\u0430\u0440\u0442\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f:<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041a\u0430\u0440\u0442\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/b><\/p>\n<div class=\"spoiler_text\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/1fb\/311\/940\/1fb31194056440bf86bfebb90685d567.png\"\/>  <\/div>\n<\/div>\n<p>  \u0421\u043e\u0441\u0442\u0430\u0432\u0438\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0442\u0435\u0441\u0442 \u043a\u0435\u0439\u0441\u044b:  <\/p>\n<ul>\n<li>\u041e\u0442\u043a\u0440\u044b\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0432\u0441\u0435\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 <\/li>\n<li>\u0412\u0432\u0435\u0441\u0442\u0438 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u043d\u0430\u0436\u0430\u0442\u044c \u043a\u043d\u043e\u043f\u043a\u0443 Search<br \/> \n<ul>\n<li>\u0414\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u044b \u2014 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u0432, \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445.<\/li>\n<li>\u0414\u0430\u043d\u043d\u044b\u0435 \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u044b \u2014 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043e\u0448\u0438\u0431\u043a\u0438.<\/li>\n<\/ul>\n<\/li>\n<li>\u041f\u0435\u0440\u0435\u0439\u0442\u0438 \u043d\u0430 \u0432\u0442\u043e\u0440\u043e\u0439 \u044d\u043a\u0440\u0430\u043d, \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0438\u043c\u0435\u043d\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f.<br \/> \n<ul>\n<li>\u041f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043a\u0438 \u0431\u0440\u0430\u043d\u0447\u0435\u0439 \u0438 \u043a\u043e\u043d\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u0440\u043e\u0432, \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445<\/li>\n<li>\u041a\u0430\u043a\u043e\u0439 \u0442\u043e \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u043e\u0432 \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d (\u0434\u0432\u0430 \u0442\u0435\u0441\u0442\u0430), \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0430, \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043e\u0448\u0438\u0431\u043a\u0438<\/li>\n<li>\u041e\u0431\u0430 \u0441\u043f\u0438\u0441\u043a\u0430 \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u044b, \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043e\u0448\u0438\u0431\u043a\u0438<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>  \u0414\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Espresso. \u0422\u0430\u043a\u0436\u0435 \u043a\u0430\u043a \u0438 \u0434\u043b\u044f \u0434\u0440\u0443\u0433\u0438\u0445 \u0442\u0435\u0441\u0442\u043e\u0432, \u0438\u0437\u043e\u043b\u0438\u0440\u0443\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043e\u0442 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u043e\u043a\u043e\u0432 \u0438 \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0445 json \u0444\u0430\u0439\u043b\u043e\u0432. \u041f\u043e\u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u043c \u0432 \u044d\u0442\u043e\u043c Dagger 2 \u0438 \u043f\u043e\u0434\u043c\u0435\u043d\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432:<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041a\u043e\u0434 MockTestRunner \u0438 TestApp<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">public class MockTestRunner extends AndroidJUnitRunner {    @Override    public Application newApplication(            ClassLoader cl, String className, Context context)            throws InstantiationException,            IllegalAccessException,            ClassNotFoundException {        return super.newApplication(                cl, TestApp.class.getName(), context);    } }  public class TestApp extends App {    @Override    protected TestComponent buildComponent() {        return DaggerTestComponent.builder().build();    } } <\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041f\u0440\u0438\u043c\u0435\u0440 \u0442\u0435\u0441\u0442\u043e\u0432 Espresso<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">@Test public void testGetUserRepo() {    apiConfig.setCorrectAnswer();    onView(withId(R.id.edit_text)).perform(clearText());    onView(withId(R.id.edit_text)).perform(typeText(TestConst.TEST_OWNER));    onView(withId(R.id.button_search)).perform(click());     onView(withId(R.id.recycler_view)).check(EspressoTools.hasItemsCount(7));     onView(withId(R.id.recycler_view)).check(EspressoTools.hasViewWithTextAtPosition(0, &quot;Android-Rate&quot;));    onView(withId(R.id.recycler_view)).check(EspressoTools.hasViewWithTextAtPosition(1, &quot;android-simple-architecture&quot;));    onView(withId(R.id.recycler_view)).check(EspressoTools.hasViewWithTextAtPosition(2, TestConst.TEST_REPO)); }  @Test public void testGetUserRepoError() {    apiConfig.setErrorAnswer();    onView(withId(R.id.edit_text)).perform(clearText());    onView(withId(R.id.edit_text)).perform(typeText(TestConst.TEST_OWNER));    onView(withId(R.id.button_search)).perform(click());     onView(allOf(withId(android.support.design.R.id.snackbar_text), withText(TestConst.TEST_ERROR)))            .check(matches(isDisplayed()));     onView(withId(R.id.recycler_view)).check(EspressoTools.hasItemsCount(0)); }<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  \u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u043f\u0438\u0448\u0435\u043c \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0442\u0435\u0441\u0442\u044b \u043f\u043e \u0442\u0435\u0441\u0442 \u043a\u0435\u0439\u0441\u0430\u043c.<br \/>  \u0417\u0430\u043a\u043e\u043d\u0447\u0438\u0432 \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 Espresso, \u043c\u044b \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043f\u043e\u043a\u0440\u043e\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043c\u043e\u0434\u0443\u043b\u044c\u043d\u044b\u043c\u0438, \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u043c\u0438 \u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0442\u0435\u0441\u0442\u0430\u043c\u0438. <\/p>\n<p>  <a name=\"33\"><\/a><\/p>\n<h4>\u0428\u0430\u0433 7. TDD<\/h4>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/66e\/106\/862\/66e1068626044e29ae6075d9c113b3f5.png\"\/><\/p>\n<p>  <a href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%A0%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0_%D1%87%D0%B5%D1%80%D0%B5%D0%B7_%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5\">\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0447\u0435\u0440\u0435\u0437 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/a> (Test-driven development) \u2014 \u0442\u0435\u0445\u043d\u0438\u043a\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e\u0433\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0447\u0435\u0440\u0435\u0437 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432.<\/p>\n<p>  \u0412 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u0432\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0442\u0440\u0438 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u044e\u0449\u0438\u0445\u0441\u044f \u0448\u0430\u0433\u0430:<br \/>  \u2014 \u041d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0441\u0442 \u0434\u043b\u044f \u043d\u043e\u0432\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c;<br \/>  \u2014 \u041d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u043e\u0439\u0434\u0435\u0442 \u0442\u0435\u0441\u0442;<br \/>  \u2014 \u041f\u0440\u043e\u0432\u0435\u0441\u0442\u0438 \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433 \u043d\u043e\u0432\u043e\u0433\u043e \u0438 \u0441\u0442\u0430\u0440\u043e\u0433\u043e \u043a\u043e\u0434\u0430.<\/p>\n<p>  \u0415\u0441\u043b\u0438 \u0430\u0431\u0431\u0440\u0435\u0432\u0438\u0430\u0442\u0443\u0440\u0430 TDD \u0434\u043b\u044f \u0432\u0430\u0441 \u043d\u0435 \u0437\u043d\u0430\u043a\u043e\u043c\u0430, \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u043c \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c <a href=\"https:\/\/habrahabr.ru\/company\/rambler-co\/blog\/263087\/\">\u0441\u0442\u0430\u0442\u044c\u044e \u043e\u0442 \u043d\u0430\u0448\u0438\u0445 \u043a\u043e\u043b\u043b\u0435\u0433 \u0438\u0437 iOS \u043e\u0442\u0434\u0435\u043b\u0430<\/a> \u0438\u043b\u0438<a href=\"https:\/\/habrahabr.ru\/hub\/tdd\/\"> \u0441\u0442\u0430\u0442\u044c\u0438 \u0438\u0437 \u0445\u0430\u0431\u0430 TDD<\/a>.<\/p>\n<p>  \u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0442 3 \u0437\u0430\u043a\u043e\u043d\u0430 TDD:<\/p>\n<ul>\n<li>\u041d\u0435 \u043f\u0438\u0448\u0435\u0442\u0441\u044f production \u043a\u043e\u0434, \u043f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u0434\u043b\u044f \u043d\u0435\u0433\u043e \u0435\u0441\u0442\u044c \u043d\u0435\u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u0442\u0435\u0441\u0442;<\/li>\n<li>\u041d\u0435 \u043f\u0438\u0448\u0435\u0442\u0441\u044f \u0431\u043e\u043b\u044c\u0448\u0435 \u043a\u043e\u0434\u0430 \u044e\u043d\u0438\u0442 \u0442\u0435\u0441\u0442\u0430, \u0447\u0435\u043c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0434\u043b\u044f \u0435\u0433\u043e \u043e\u0448\u0438\u0431\u043a\u0438.<\/li>\n<li>\u041d\u0435 \u043f\u0438\u0448\u0435\u0442\u0441\u044f \u0431\u043e\u043b\u044c\u0448\u0435 production \u043a\u043e\u0434\u0430, \u0447\u0435\u043c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0434\u043b\u044f \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043d\u0435\u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0435\u0433\u043e \u0442\u0435\u0441\u0442\u0430.<\/li>\n<\/ul>\n<p>  \u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c progress bar \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u0438\u0437 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430. \u041e\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u044f\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u043a\u043e\u0433\u0434\u0430 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0438\u0441\u0447\u0435\u0437\u0430\u0442\u044c \u043a\u043e\u0433\u0434\u0430 \u0434\u0430\u043d\u043d\u044b\u0435 \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u044b \u0438\u043b\u0438 \u043f\u043e\u044f\u0432\u0438\u043b\u0430\u0441\u044c \u043e\u0448\u0438\u0431\u043a\u0430. \u0412\u0441\u044e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0431\u0443\u0434\u0435\u043c \u0432\u0435\u0441\u0442\u0438 \u043f\u043e TDD.<\/p>\n<p>  \u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0434\u0430\u043d\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0437\u0430\u0442\u0440\u043e\u043d\u0435\u0442 \u043f\u0440\u0435\u0437\u0435\u043d\u0442\u0435\u0440\u044b \u0438 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u044b, \u043c\u0430\u043f\u043f\u0435\u0440\u044b \u0438 \u0434\u0430\u0442\u0430 \u0441\u043b\u043e\u0439 \u043e\u0441\u0442\u0430\u044e\u0442\u0441\u044f \u0431\u0435\u0437 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439.<\/p>\n<h5>\u041f\u0440\u0435\u0437\u0435\u043d\u0442\u0435\u0440\u044b<\/h5>\n<p>  \u041d\u0430\u0447\u043d\u0435\u043c \u0441\u043e \u0441\u043f\u0438\u0441\u043a\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u0432. \u041f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b:<\/p>\n<pre><code class=\"java\">public interface RepoListView extends View {     void showRepoList(List&lt;Repository&gt; list);     void showEmptyList();     String getUserName();     void startRepoInfoFragment(Repository repository);    \/\/New    void showLoading();    void hideLoading(); } <\/code><\/pre>\n<p>  <\/p>\n<h6>\u041f\u0435\u0440\u0432\u044b\u0439 \u044d\u0442\u0430\u043f.<\/h6>\n<p>  \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u0438\u0448\u0435\u043c \u0442\u0435\u0441\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442, \u0447\u0442\u043e \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e\u0439 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0431\u044b\u043b \u0432\u044b\u0437\u0432\u0430\u043d \u043c\u0435\u0442\u043e\u0434 showLoading \u0443 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u0430:<\/p>\n<pre><code class=\"java\">@Test public void testShowLoading() {    repoListPresenter.onSearchButtonClick();    verify(mockView).showLoading(); } <\/code><\/pre>\n<p>  \u041a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u043d\u0435\u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u0442\u0435\u0441\u0442, \u043f\u0438\u0448\u0435\u043c \u043a\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u043e\u0439\u0434\u0435\u0442 \u0435\u0433\u043e:<\/p>\n<pre><code class=\"java\">public void onSearchButtonClick() {    String name = view.getUserName();    if (TextUtils.isEmpty(name)) return;    view.showLoading();    \/\/ --- some code --- } <\/code><\/pre>\n<p>  \u0420\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u0442\u044c \u043f\u043e\u043a\u0430 \u043d\u0435\u0447\u0435\u0433\u043e.<\/p>\n<p>  \u041d\u0430 \u044d\u0442\u043e\u043c \u043f\u0435\u0440\u0432\u0430\u044f \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u043e TDD \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043b\u0430\u0441\u044c. \u041c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u043d\u043e\u0432\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0438 \u0442\u0435\u0441\u0442 \u0434\u043b\u044f \u043d\u0435\u0435. <\/p>\n<h6>\u0412\u0442\u043e\u0440\u043e\u0439 \u044d\u0442\u0430\u043f.<\/h6>\n<p>  \u041d\u0430\u043f\u0438\u0448\u0435\u043c \u0442\u0435\u0441\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442, \u0447\u0442\u043e \u043f\u043e\u0441\u043b\u0435 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e\u0439 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0431\u044b\u043b \u0432\u044b\u0437\u0432\u0430\u043d \u043c\u0435\u0442\u043e\u0434 hideLoading \u0443 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u0430:<\/p>\n<pre><code class=\"java\">@Test public void testHideLoading() {    repoListPresenter.onSearchButtonClick();    verify(mockView).hideLoading(); } <\/code><\/pre>\n<p>  \u041f\u0438\u0448\u0435\u043c \u043a\u043e\u0434 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u043e\u0439\u0434\u0435\u0442 \u0442\u0435\u0441\u0442:<\/p>\n<pre><code class=\"java\">\/\/-- view.showLoading(); Subscription subscription = model.getRepoList(name)        .map(repoListMapper)        .subscribe(new Observer&lt;List&lt;Repository&gt;&gt;() {            @Override            public void onCompleted() {               view.hideLoading();            }             @Override            public void onError(Throwable e) {                view.showError(e.getMessage());            }             @Override            public void onNext(List&lt;Repository&gt; list) {                if (list != null && !list.isEmpty()) {                    repoList = list;                    view.showRepoList(list);                } else {                    view.showEmptyList();                }            }        }); <\/code><\/pre>\n<p>  \u0420\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433 \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f.<\/p>\n<h6>\u0422\u0440\u0435\u0442\u0438\u0439 \u0438 \u0447\u0435\u0442\u0432\u0435\u0440\u0442\u044b\u0439 \u044d\u0442\u0430\u043f\u044b.<\/h6>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0442\u0435\u0441\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442, \u0447\u0442\u043e \u043f\u0440\u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u0438 \u043e\u0448\u0438\u0431\u043a\u0438 \u0431\u044b\u043b\u0438 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b \u0432\u044b\u0437\u0432\u0430\u043d\u044b \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b.<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u0422\u0435\u0441\u0442\u044b \u043d\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043e\u0448\u0438\u0431\u043a\u0438<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">@Test public void testShowLoadingOnError() {    doAnswer(invocation -&gt; Observable.error(new Throwable(TestConst.TEST_ERROR)))            .when(model)            .getRepoList(TestConst.TEST_OWNER);    repoListPresenter.onSearchButtonClick();    verify(mockView).showLoading(); }  @Test public void testHideLoadingOnError() {    doAnswer(invocation -&gt; Observable.error(new Throwable(TestConst.TEST_ERROR)))            .when(model)            .getRepoList(TestConst.TEST_OWNER);    repoListPresenter.onSearchButtonClick();    verify(mockView).hideLoading(); }<\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041a\u043e\u0434 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043e\u0448\u0438\u0431\u043a\u0438<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">\/\/--   @Override            public void onError(Throwable e) {                   view.showError(e.getMessage());  \t\t      view.hideLoading();            } \/\/--<\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0420\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433 \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f. \u0420\u0430\u0431\u043e\u0442\u0430 \u0441 Repo List Presenter \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430, \u0442\u0435\u043f\u0435\u0440\u044c \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a Repo Info Presenter.<\/p>\n<h5>Repo Info Presenter<\/h5>\n<p>  \u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u043c\u0443 \u0448\u0430\u0433\u0443, \u043f\u0438\u0448\u0435\u043c \u0442\u0435\u0441\u0442\u044b \u0438 \u043a\u043e\u0434 \u0434\u043b\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0439 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u0422\u0435\u0441\u0442\u044b \u0434\u043b\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0439 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">@Test public void testShowLoading() {    repoInfoPresenter.onCreateView(null);    verify(mockView).showLoading(); }  @Test public void testHideLoading() {    repoInfoPresenter.onCreateView(null);    verify(mockView).hideLoading(); }<\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041a\u043e\u0434 \u0434\u043b\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0439 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">public void loadData() {    String owner = repository.getOwnerName();    String name = repository.getRepoName();     view.showLoading();    Subscription subscriptionBranches = model.getRepoBranches(owner, name)            .map(branchesMapper)            .subscribe(new Observer&lt;List&lt;Branch&gt;&gt;() {                @Override                public void onCompleted() {                    hideInfoLoadingState();                }                 @Override                public void onError(Throwable e) {                    view.showError(e.getMessage());                }                 @Override                public void onNext(List&lt;Branch&gt; list) {                    branchList = list;                    view.showBranches(list);                }            });    addSubscription(subscriptionBranches);     Subscription subscriptionContributors = model.getRepoContributors(owner, name)            .map(contributorsMapper)            .subscribe(new Observer&lt;List&lt;Contributor&gt;&gt;() {                @Override                public void onCompleted() {                    hideInfoLoadingState();                }                 @Override                public void onError(Throwable e) {                    view.showError(e.getMessage());                }                 @Override                public void onNext(List&lt;Contributor&gt; list) {                    contributorList = list;                    view.showContributors(list);                }            });     addSubscription(subscriptionContributors); }  protected void hideInfoLoadingState() {    countCompletedSubscription++;     if (countCompletedSubscription == COUNT_SUBSCRIPTION) {        view.hideLoading();        countCompletedSubscription = 0;    } }<\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0420\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433.<br \/>  \u041a\u0430\u043a \u0432\u0438\u0434\u043d\u043e, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0439 \u043a\u043e\u0434 \u0434\u043b\u044f \u0434\u0432\u0443\u0445 \u043f\u0440\u0435\u0437\u0435\u043d\u0442\u0435\u0440\u043e\u0432 (\u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0438 \u0441\u043a\u0440\u044b\u0442\u044c \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438, \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u043e\u0448\u0438\u0431\u043a\u0443). \u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u043d\u0435\u0441\u0442\u0438 \u0435\u0433\u043e \u0432 \u043e\u0431\u0449\u0438\u0439 \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 BasePresenter. \u0412\u044b\u043d\u043e\u0441\u0438\u043c \u043c\u0435\u0442\u043e\u0434\u044b showLoadingState() hideLoadingState() \u0438 showError(Throwable e) \u0432 BasePresenter<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041a\u043e\u0434 BasePresenter<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">protected abstract View getView();  protected void showLoadingState() {    getView().showLoadingState(); }  protected void hideLoadingState() {    getView().hideLoadingState(); }  protected void showError(Throwable e) {    getView().showError(e.getMessage()); } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0420\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043c RepoInfoPresenter \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c, \u0447\u0442\u043e \u043f\u0440\u043e\u0445\u043e\u0434\u044f\u0442 \u0432\u0441\u0435 \u0442\u0435\u0441\u0442\u044b. \u041d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0435\u043c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433 RepoListPresenter \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0431\u0430\u0437\u043e\u0432\u044b\u043c \u043a\u043b\u0430\u0441\u0441\u043e\u043c. <\/p>\n<p>  \u0414\u0430\u043b\u0435\u0435 \u043f\u0438\u0448\u0435\u043c \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0442\u0435\u0441\u0442\u044b, \u0430 \u043f\u043e\u0442\u043e\u043c \u043a\u043e\u0434 \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043e\u0448\u0438\u0431\u043e\u043a \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 (\u0434\u043b\u044f RepoInfoPresenter).<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u0422\u0435\u0441\u0442\u044b \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043e\u0448\u0438\u0431\u043e\u043a \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">@Test public void testShowLoadingOnError() {    doAnswer(invocation -&gt; Observable.error(new Throwable(TestConst.TEST_ERROR)))            .when(model)            .getRepoContributors(TestConst.TEST_OWNER, TestConst.TEST_REPO);    doAnswer(invocation -&gt; Observable.error(new Throwable(TestConst.TEST_ERROR)))            .when(model)            .getRepoBranches(TestConst.TEST_OWNER, TestConst.TEST_REPO);    repoInfoPresenter.onCreateView(null);    verify(mockView).showLoading(); }  @Test public void testHideLoadingOnError() {    doAnswer(invocation -&gt; Observable.error(new Throwable(TestConst.TEST_ERROR)))            .when(model)            .getRepoContributors(TestConst.TEST_OWNER, TestConst.TEST_REPO);    doAnswer(invocation -&gt; Observable.error(new Throwable(TestConst.TEST_ERROR)))            .when(model)            .getRepoBranches(TestConst.TEST_OWNER, TestConst.TEST_REPO);    repoInfoPresenter.onCreateView(null);    verify(mockView).hideLoading(); }  @Test public void testShowLoadingOnErrorBranches() {    doAnswer(invocation -&gt; Observable.error(new Throwable(TestConst.TEST_ERROR)))            .when(model)            .getRepoBranches(TestConst.TEST_OWNER, TestConst.TEST_REPO);    repoInfoPresenter.onCreateView(null);    verify(mockView).showLoading(); }  @Test public void testHideLoadingOnErrorBranches() {    doAnswer(invocation -&gt; Observable.error(new Throwable(TestConst.TEST_ERROR)))            .when(model)            .getRepoBranches(TestConst.TEST_OWNER, TestConst.TEST_REPO);    repoInfoPresenter.onCreateView(null);    verify(mockView).hideLoading(); }<\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041a\u043e\u0434 \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043e\u0448\u0438\u0431\u043e\u043a \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">showLoadingState(); Subscription subscriptionBranches = model.getRepoBranches(owner, name)        .map(branchesMapper)        .subscribe(new Observer&lt;List&lt;Branch&gt;&gt;() {            @Override            public void onCompleted() {                hideInfoLoadingState();            }             @Override            public void onError(Throwable e) {                hideInfoLoadingState();                showError(e);            }             @Override            public void onNext(List&lt;Branch&gt; list) {                branchList = list;                view.showBranches(list);            }        }); addSubscription(subscriptionBranches);  Subscription subscriptionContributors = model.getRepoContributors(owner, name)        .map(contributorsMapper)        .subscribe(new Observer&lt;List&lt;Contributor&gt;&gt;() {            @Override            public void onCompleted() {                hideInfoLoadingState();            }             @Override            public void onError(Throwable e) {                hideInfoLoadingState();                showError(e);            }             @Override            public void onNext(List&lt;Contributor&gt; list) {                contributorList = list;                view.showContributors(list);            }        });<\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u041d\u0430 \u044d\u0442\u043e\u043c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043f\u0440\u0435\u0437\u0435\u043d\u0442\u0435\u0440\u043e\u0432 \u0437\u0430\u043a\u043e\u043d\u0447\u0435\u043d\u0430. \u041f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043a \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u0430\u043c.<\/p>\n<h5>\u0424\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u044b<\/h5>\n<p>  Progress bar, \u043a\u0430\u043a \u043e\u0431\u0449\u0438\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442, \u0431\u0443\u0434\u0435\u0442 \u043b\u0435\u0436\u0430\u0442\u044c \u0432 activity, \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u044b \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0443 activity \u043c\u0435\u0442\u043e\u0434\u044b showProgressBar() \u0438 hideProgressBar(), \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u043a\u0430\u0436\u0443\u0442 \u0438\u043b\u0438 \u0441\u043f\u0440\u044f\u0447\u0443\u0442 progress bar. \u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 activity \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 ActivityCallback. \u041f\u043e \u043e\u043f\u044b\u0442\u0443 \u043f\u0440\u0435\u0437\u0435\u043d\u0442\u0435\u0440\u043e\u0432, \u043c\u043e\u0436\u0435\u043c \u0441\u0440\u0430\u0437\u0443 \u0434\u043e\u0433\u0430\u0434\u0430\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u043d\u0430\u043c \u0431\u0443\u0434\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c \u043e\u0431\u0449\u0438\u0439 \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u2014 BaseFragment. \u0412 \u043d\u0435\u043c \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c\u0441\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 activity. <\/p>\n<p>  \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u0438\u0448\u0435\u043c \u0442\u0435\u0441\u0442\u044b, \u0430 \u043f\u043e\u0442\u043e\u043c \u043a\u043e\u0434, \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u0430 \u0441 activity:<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u0422\u0435\u0441\u0442\u044b Base Fragment<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">@Test public void testAttachActivityCallback() throws Exception {      assertNotNull(baseFragment.activityCallback); }  @Test public void testShowLoadingState() throws Exception {    baseFragment.showLoading();    verify(activity).showProgressBar(); }  @Test public void testHideLoadingState() throws Exception {    baseFragment.hideLoading();    verify(activity).hideProgressBar(); }<\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041a\u043e\u0434 Base Fragment<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">@Override public void onAttach(Activity activity) {    super.onAttach(activity);     try {        activityCallback = (ActivityCallback) activity;    } catch (ClassCastException e) {        throw new ClassCastException(activity.toString()                + &quot; must implement activityCallback&quot;);    } } @Override public void showLoading() {    activityCallback.showProgressBar(); }  @Override public void hideLoading() {    activityCallback.hideProgressBar(); }<\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0420\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433 \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f, \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043a activity.<\/p>\n<h5>Acitivity<\/h5>\n<p>  \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u043c \u0448\u0430\u0433\u043e\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 Activity. \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u044c (setVisibility) progressBar \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u044b. \u0412 \u0442\u0435\u0441\u0442\u0430\u0445 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0447\u0442\u043e progressBar \u043d\u0430\u0439\u0434\u0435\u043d \u0438 \u0440\u0430\u0431\u043e\u0442\u0443 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 showProgressBar \u0438 hideProgressBar.<\/p>\n<p>  \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u0438\u0448\u0435\u043c \u0442\u0435\u0441\u0442\u044b:<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u0422\u0435\u0441\u0442\u044b Activity<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">@Test public void testHaveProgressBar() throws Exception {     assertNotNull(progressBar); }  @Test public void testShowProgressBar() throws Exception {    mainActivity.showProgressBar();    verify(progressBar).setVisibility(View.VISIBLE); }  @Test public void testHideProgressBar() throws Exception {    mainActivity.hideProgressBar();    verify(progressBar).setVisibility(View.INVISIBLE); }<\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u041f\u043e\u0442\u043e\u043c \u043f\u0438\u0448\u0435\u043c \u043a\u043e\u0434:<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041a\u043e\u0434 Activity<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">@Bind(R.id.toolbar_progress_bar) protected ProgressBar progressBar;  \/\/---- some code ----  @Override public void showProgressBar() {    progressBar.setVisibility(View.VISIBLE); }  @Override public void hideProgressBar() {    progressBar.setVisibility(View.INVISIBLE); }<\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0412\u0441\u0435 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u043e, \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433 \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f.<\/p>\n<p>  \u041d\u0430 \u044d\u0442\u043e\u043c \u043c\u044b \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 progress bar \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0442\u0435\u0445\u043d\u0438\u043a\u0438 TDD. <\/p>\n<p>  <a name=\"34\"><\/a><\/p>\n<h4>\u0428\u0430\u0433 8. \u0427\u0442\u043e \u0434\u0430\u043b\u044c\u0448\u0435?<\/h4>\n<p>  \u0418\u0437\u0443\u0447\u0438\u0432 TDD \u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u0432 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438, \u043c\u044b \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0414\u043b\u044f \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0433\u043e \u0440\u0430\u0437\u0432\u0438\u0442\u0438\u044f \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u043a \u043f\u0440\u043e\u0447\u0442\u0435\u043d\u0438\u044e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0441\u0442\u0430\u0442\u044c\u0438:<\/p>\n<p>  <b>Android Clean Architecture<\/b><br \/>  <a href=\"http:\/\/fernandocejas.com\/2014\/09\/03\/architecting-android-the-clean-way\/\">Android Clean Architecture<\/a> \u2014 \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u043e\u0442 Fernando Cejas, \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 <a href=\"http:\/\/blog.8thlight.com\/uncle-bob\/2012\/08\/13\/the-clean-architecture.html\">Clean Architecture \u043e\u0442 \u0414\u044f\u0434\u044e\u0448\u043a\u0438 \u0411\u043e\u0431\u0430<\/a>. \u0420\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 3 \u0441\u043b\u043e\u044f\u043c\u0438 Presentation Layer, Domain Layer \u0438 Data Layer. \u0415\u0441\u0442\u044c <a href=\"https:\/\/habrahabr.ru\/post\/250659\/\">\u043f\u0435\u0440\u0435\u0432\u043e\u0434 \u043d\u0430 habrahabr.<\/a> <\/p>\n<p>  <b>VIPER<\/b> <br \/>  VIPER (View, Interactor, Presenter, Entity \u0438 Routing) \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0432\u0441\u0435 \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u0435\u043d, \u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u0441\u044f \u0441 \u043d\u0438\u043c \u043c\u043e\u0436\u043d\u043e \u0432 \u0441\u0442\u0430\u0442\u044c\u0435 <a href=\"https:\/\/habrahabr.ru\/company\/rambler-co\/blog\/277003\/\">Android VIPER \u043d\u0430 \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0439 \u0442\u044f\u0433\u0435<\/a> \u043e\u0442  <a href=\"https:\/\/habrahabr.ru\/users\/vikkos\/\" class=\"user_link\">VikkoS<\/a>. \u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u044b VIPER \u043e\u0441\u0432\u0435\u0449\u0435\u043d\u044b <a href=\"https:\/\/habrahabr.ru\/company\/rambler-co\/blog\/273949\/\">\u0432 \u0441\u0442\u0430\u0442\u044c\u044f\u0445 \u0438 \u0434\u043e\u043a\u043b\u0430\u0434\u0430\u0445 \u043d\u0430\u0448\u0438\u0445 \u043a\u043e\u043b\u043b\u0435\u0433 \u0438\u0437 \u043e\u0442\u0434\u0435\u043b\u0430 iOS.<\/a><\/p>\n<p>  <b>Mosby<\/b> <br \/>  Mosby \u2014 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u0430\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f MVP \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439. \u0421\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0432 \u0441\u0435\u0431\u0435 \u0432\u0441\u0435 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b \u0438 \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u043a\u043b\u0430\u0441\u0441\u044b. \u0421\u0430\u0439\u0442: <a href=\"http:\/\/hannesdorfmann.com\/mosby\/\">http:\/\/hannesdorfmann.com\/mosby\/<\/a> Github: <a href=\"https:\/\/github.com\/sockeqwe\/mosby\">https:\/\/github.com\/sockeqwe\/mosby<\/a><\/p>\n<p>  <b>Android Application Architecture<\/b><br \/>  \u0425\u043e\u0440\u043e\u0448\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u043f\u0440\u043e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443 \u043e\u0442 <a href=\"https:\/\/labs.ribot.co.uk\/android-application-architecture-8b6e34acda65#.d7yggc7a7\">Ribot team \u2014 Android Application Architecture<\/a>. \u0420\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044f c AsyncTask \u043d\u0430 RxJava. \u0421\u043e\u0432\u0441\u0435\u043c \u043d\u0435\u0434\u0430\u0432\u043d\u043e \u0432\u044b\u0448\u0435\u043b <a href=\"https:\/\/habrahabr.ru\/post\/278815\/\">\u043f\u0435\u0440\u0435\u0432\u043e\u0434 \u043d\u0430 habrahabr.<\/a><\/p>\n<p>  <b>Android Development Culture Document<\/b><br \/>  <a href=\"http:\/\/artemzin.com\/blog\/android-development-culture-the-document-qualitymatters\/\">Android Development Culture Document #qualitymatters \u043e\u0442  <a href=\"https:\/\/habrahabr.ru\/users\/artem_zin\/\" class=\"user_link\">Artem_zin<\/a><\/a>. \u041e\u0442\u043b\u0438\u0447\u043d\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u0438 \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u043e\u0442 Artem Zinnatullin. \u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u044e\u0442\u0441\u044f 8 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u043e\u0432 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 android \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u043f\u043e\u0434\u043a\u0440\u0435\u043f\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u0441\u0435 \u044d\u0442\u043e <a href=\"https:\/\/github.com\/artem-zinnatullin\/qualitymatters\">\u043f\u0440\u0438\u043c\u0435\u0440\u043e\u043c \u043d\u0430 Github.<\/a><\/p>\n<p>  <a name=\"35\"><\/a><\/p>\n<h4>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h4>\n<p>  \u0412 \u044d\u0442\u043e\u043c \u0446\u0438\u043a\u043b\u0435 \u0441\u0442\u0430\u0442\u0435\u0439 \u043c\u044b \u043f\u0440\u043e\u0448\u043b\u0438 \u0432\u0441\u0435 \u044d\u0442\u0430\u043f\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041d\u0430\u0447\u0430\u043b\u0438 \u043c\u044b c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 MVP, \u0443\u0441\u043b\u043e\u0436\u043d\u044f\u044f \u0435\u0435 \u043f\u043e \u0445\u043e\u0434\u0443 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u043e\u0432\u044b\u0445 \u0444\u0438\u0447. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438: RxJava \u0438 RxAndroid \u0434\u043b\u044f \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0438\u0437\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043e\u0442 callback-\u043e\u0432, Retrofit \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0441\u0435\u0442\u044c\u044e, Butterknife \u0434\u043b\u044f \u0431\u044b\u0441\u0442\u0440\u043e\u0433\u043e \u0438 \u043b\u0435\u0433\u043a\u043e\u0433\u043e \u043f\u043e\u0438\u0441\u043a\u0430 view. Dagger 2 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u043b \u0432\u0441\u0435\u043c\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438 \u0438 \u043e\u043a\u0430\u0437\u0430\u043b \u043d\u0430\u043c \u043d\u0435\u043e\u0446\u0435\u043d\u0438\u043c\u0443\u044e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u043f\u0440\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u0442\u0435\u0441\u0442\u043e\u0432. \u0421\u0430\u043c\u0438 \u0442\u0435\u0441\u0442\u044b \u043c\u044b \u043f\u0438\u0441\u0430\u043b\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e jUnit, Robolectric, Mockito \u0438 MockWebServer. \u0410 Espresso \u0438\u0437\u0431\u0430\u0432\u0438\u043b \u043d\u0430\u0448\u0438\u0445 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0449\u0438\u043a\u043e\u0432 \u043e\u0442 \u043c\u0443\u043a \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. <\/p>\n<p>  \u041c\u044b \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043f\u043e\u043a\u0440\u044b\u043b\u0438 \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u0442\u0435\u0441\u0442\u0430\u043c\u0438. Unit \u0442\u0435\u0441\u0442\u044b \u0438\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044e\u0442 \u043a\u0430\u0436\u0434\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442, \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u0442\u0435\u0441\u0442\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044e\u0442 \u0438\u0445 \u043e\u0431\u0449\u0435\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435, \u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u0442\u0435\u0441\u0442\u044b \u0441\u043c\u043e\u0442\u0440\u044f\u0442 \u043d\u0430 \u0432\u0441\u0435 \u044d\u0442\u043e \u0441\u043e \u0441\u0442\u043e\u0440\u043e\u043d\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u041f\u0440\u0438 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043d\u0435 \u0431\u043e\u044f\u0442\u044c\u0441\u044f (\u043d\u0443 \u0438\u043b\u0438 \u043f\u043e\u0447\u0442\u0438 \u043d\u0435 \u0431\u043e\u044f\u0442\u044c\u0441\u044f), \u0447\u0442\u043e \u043f\u043e\u043b\u043e\u043c\u0430\u0435\u043c \u043a\u0430\u043a\u0438\u0435 \u0442\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u0438 \u0447\u0442\u043e \u0442\u043e \u043e\u0442\u0432\u0430\u043b\u0438\u0442\u0441\u044f, \u0430 \u0431\u0430\u0433\u0438 \u043f\u0440\u043e\u043b\u0435\u0437\u0443\u0442 \u0432 \u0440\u0435\u043b\u0438\u0437. \u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f TDD, \u0431\u043e\u043b\u044c\u0448\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u043d\u0430\u0448\u0435\u0433\u043e \u043a\u043e\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043a\u0440\u044b\u0442\u0430 \u0442\u0435\u0441\u0442\u0430\u043c\u0438 (\u043d\u0435\u0442 \u0442\u0435\u0441\u0442\u0430, \u043d\u0435\u0442 \u0438 \u043a\u043e\u0434\u0430). \u041d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0447\u0430\u0441\u0442\u0438\u0447\u043d\u043e\u0433\u043e \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044f \u0438\u043b\u0438 \u201c\u043a\u043e\u0434 \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0438, \u0430 \u043d\u0430 \u0442\u0435\u0441\u0442\u044b \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043d\u0435 \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c\u201d.<\/p>\n<p>  \u0412\u0435\u0441\u044c \u043a\u043e\u0434 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043d\u0430 <a href=\"https:\/\/github.com\/andrey7mel\/android-step-by-step\">Github (https:\/\/github.com\/andrey7mel\/android-step-by-step)<\/a> <br \/>  \u041d\u0430\u0434\u0435\u044e\u0441\u044c, \u044d\u0442\u0430 \u0441\u0435\u0440\u0438\u044f \u0441\u0442\u0430\u0442\u0435\u0439 \u0432\u0430\u043c \u043f\u043e\u043d\u0440\u0430\u0432\u0438\u043b\u0430\u0441\u044c \u0438 \u043e\u043a\u0430\u0437\u0430\u043b\u0430\u0441\u044c \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u0439, \u0441\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435!               <\/p>\n<div class=\"clear\"><\/div>\n<p> \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:\/\/habrahabr.ru\/post\/279799\/\"> https:\/\/habrahabr.ru\/post\/279799\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>       <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/ddd\/981\/4fe\/ddd9814fe65645ffaa655874a6fd9dc0.jpg\"\/><\/p>\n<p>  \u0412 <a href=\"https:\/\/habrahabr.ru\/company\/rambler-co\/blog\/275943\/\">\u043f\u0435\u0440\u0432\u043e\u0439<\/a> \u0438 <a href=\"https:\/\/habrahabr.ru\/company\/rambler-co\/blog\/277343\/\">\u0432\u0442\u043e\u0440\u043e\u0439 \u0447\u0430\u0441\u0442\u044f\u0445<\/a> \u0441\u0442\u0430\u0442\u044c\u0438 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u043b\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 Github, \u0432\u043d\u0435\u0434\u0440\u0438\u043b\u0438 Dagger 2 \u0438 \u043f\u043e\u043a\u0440\u044b\u043b\u0438 \u043a\u043e\u0434 unit \u0442\u0435\u0441\u0442\u0430\u043c\u0438. \u0412 \u0437\u0430\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u0442\u0435\u0441\u0442\u044b, \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0442\u0435\u0445\u043d\u0438\u043a\u0443 TDD \u0438 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0441 \u0435\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435\u043c \u043d\u043e\u0432\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u0434\u0441\u043a\u0430\u0436\u0435\u043c, \u0447\u0442\u043e \u0447\u0438\u0442\u0430\u0442\u044c \u0434\u0430\u043b\u044c\u0448\u0435.   <\/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-276857","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/276857","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=276857"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/276857\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=276857"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=276857"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=276857"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}