рд╕реНрд╡рдЪреНрдЫ рд╕реНрд╡рд┐рдлреНрдЯ рд╡рд╛рд╕реНрддреБрдХрд▓рд╛ рдореЗрдВ рдЗрдХрд╛рдИ рдкрд░реАрдХреНрд╖рдг

рдирдорд╕реНрдХрд╛рд░ рдкрд╛рдардХ рдЬреА!


рдпрд╣ рдХреЛрдИ рд░рд╣рд╕реНрдп рдирд╣реАрдВ рд╣реИ рдХрд┐ рдкрд░реАрдХреНрд╖рдг рдХрд┐рд╕реА рднреА рд╡рд┐рдХрд╛рд╕ рдХрд╛ рдПрдХ рдЕрднрд┐рдиреНрди рдЕрдВрдЧ рд╣реИред рдкрд┐рдЫрд▓реЗ рд▓реЗрдЦреЛрдВ рдореЗрдВ, рд╣рдордиреЗ рдХреНрд▓реАрди рд╕реНрд╡рд┐рдлреНрдЯ рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░ рдХреЗ рдмреБрдирд┐рдпрд╛рджреА рдврд╛рдВрдЪреЗ рдХреЛ рдХрд╡рд░ рдХрд┐рдпрд╛ рд╣реИ, рдФрд░ рдЕрдм рдпрд╣ рд╕реАрдЦрдиреЗ рдХрд╛ рд╕рдордп рд╣реИ рдХрд┐ рдЗрд╕рдХреА рдпреВрдирд┐рдЯ рдХреЛ рдкрд░реАрдХреНрд╖рдгреЛрдВ рдХреЗ рд╕рд╛рде рдХреИрд╕реЗ рдХрд╡рд░ рдХрд┐рдпрд╛ рдЬрд╛рдПред рд╣рдо рдПрдХ рдЖрдзрд╛рд░ рдХреЗ рд░реВрдк рдореЗрдВ рд╢реНрд░рдорд┐рдХреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд▓реЗрдЦ рд╕реЗ рдкрд░рд┐рдпреЛрдЬрдирд╛ рд▓реЗрдВрдЧреЗ рдФрд░ рдореБрдЦреНрдп рдмрд┐рдВрджреБрдУрдВ рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░реЗрдВрдЧреЗ ред



рд╕рд┐рджреНрдзрд╛рдВрдд


рдирд┐рд░реНрднрд░рддрд╛ рдЗрдВрдЬреЗрдХреНрд╢рди рдФрд░ рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдЙрдиреНрдореБрдЦ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж, рдХреНрд▓реАрди рд╕реНрд╡рд┐рдлреНрдЯ рдореЗрдВ рд╕рднреА рджреГрд╢реНрдп рдШрдЯрдХ рдПрдХ рджреВрд╕рд░реЗ рд╕реЗ рд╕реНрд╡рддрдВрддреНрд░ рд╣реИрдВ рдФрд░ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдкрд░реАрдХреНрд╖рдг рдХрд┐рдП рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВред рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд░реВрдк рдореЗрдВ, рд╕рд╣рднрд╛рдЧрд┐рддрд╛ рдкреНрд░рд╕реНрддреБрддрдХрд░реНрддрд╛ рдФрд░ рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рдкрд░ рдирд┐рд░реНрднрд░ рд╣реИ, рд▓реЗрдХрд┐рди рдпреЗ рдирд┐рд░реНрднрд░рддрд╛ рд╡реИрдХрд▓реНрдкрд┐рдХ рдФрд░ рдкреНрд░реЛрдЯреЛрдХреЙрд▓-рдЖрдзрд╛рд░рд┐рдд рд╣реИрдВред рдЗрд╕ рдкреНрд░рдХрд╛рд░, рдЗрдВрдЯрд░рд╕реЗрдиреНрд╕рд░ рдкреНрд░реЗрдЬреЗрдВрдЯрд░'рдП рдФрд░ рд╡рд░реНрдХрд░'рдП рдХреЗ рдмрд┐рдирд╛ рдЕрдкрдирд╛ рдХрд╛рдо (рд╣рд╛рд▓рд╛рдВрдХрд┐ рдЕрд╡рд░) рдХрд░ рд╕рдХрддрд╛ рд╣реИ, рдФрд░ рд╣рдо рдЙрдиреНрд╣реЗрдВ рдЙрдирдХреЗ рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдХреЗ рддрд╣рдд рд╣рд╕реНрддрд╛рдХреНрд╖рд░рд┐рдд рдЕрдиреНрдп рд╡рд╕реНрддреБрдУрдВ рдХреЗ рд╕рд╛рде рднреА рдмрджрд▓ рд╕рдХрддреЗ рд╣реИрдВред


рдЪреВрдВрдХрд┐ рд╣рдо рдкреНрд░рддреНрдпреЗрдХ рдШрдЯрдХ рдХреЛ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдкрд░реАрдХреНрд╖рдг рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рд╣рдореЗрдВ рдЫрджреНрдо рдШрдЯрдХреЛрдВ рдХреЗ рд╕рд╛рде рдирд┐рд░реНрднрд░рддрд╛ рдХреЛ рдмрджрд▓рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдпрд╣ рд╣рдореЗрдВ рдЬрд╛рд╕реВрд╕реЛрдВ (рдЬрд╛рд╕реВрд╕) рдХреА рдорджрдж рдХрд░реЗрдЧрд╛ред рд╕реНрдкрд╛рдИ рдкрд░реАрдХреНрд╖рдг рдСрдмреНрдЬреЗрдХреНрдЯ рд╣реИрдВ рдЬреЛ рдЙрди рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддреЗ рд╣реИрдВ рдЬрд┐рдиреНрд╣реЗрдВ рд╣рдо рдЙрдиреНрд╣реЗрдВ рдХреЙрд▓ рдХрд░рдиреЗ рдХреА рд╡рд┐рдзрд┐ рдХреЛ рдЗрдВрдЬреЗрдХреНрдЯ рдФрд░ рдЯреНрд░реИрдХ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред рджреВрд╕рд░реЗ рд╢рдмреНрджреЛрдВ рдореЗрдВ, рд╣рдо рдкреНрд░рд╕реНрддреБрддрдХрд░реНрддрд╛ рдФрд░ рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рдХреЗ рд▓рд┐рдП рд╕реНрдкрд╛рдИ рдмрдирд╛рддреЗ рд╣реИрдВ, рдФрд░ рдлрд┐рд░ рдЙрдиреНрд╣реЗрдВ рд╡рд┐рдзрд┐ рдХреЙрд▓ рдХреЛ рдЯреНрд░реИрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЗрдВрдЯрд░реЗрдХреНрдЯрд░ рдореЗрдВ рдЗрдВрдЬреЗрдХреНрдЯ рдХрд░рддреЗ рд╣реИрдВред



рдирд┐рд╖реНрдкрдХреНрд╖рддрд╛ рдореЗрдВ, рдореИрдВ рдпрд╣ рдЬреЛрдбрд╝рддрд╛ рд╣реВрдВ рдХрд┐ рдЯреЗрд╕реНрдЯ рдСрдмреНрдЬреЗрдХреНрдЯ ( рдЯреЗрд╕реНрдЯ рдбрдмрд▓реНрд╕ ) рдбрдореА , рдлреЗрдХ , рд╕реНрдЯрдм рдФрд░ рдореЙрдХ рднреА рд╣реИрдВ ред рд▓реЗрдХрд┐рди рдЗрд╕ рд▓реЗрдЦ рдХреЗ рдврд╛рдВрдЪреЗ рдХреЗ рднреАрддрд░, рд╣рдо рдЙрдиреНрд╣реЗрдВ рдкреНрд░рднрд╛рд╡рд┐рдд рдирд╣реАрдВ рдХрд░реЗрдВрдЧреЗред рдпрд╣рд╛рдБ рдФрд░ рдкрдврд╝реЗрдВ - TestDoubles


рдЕрднреНрдпрд╛рд╕


рд╢рдмреНрджреЛрдВ рдХреЗ рд╕рд╛рде рд╕рдорд╛рдкреНрдд, рдЪрд▓реЛ рд╡реНрдпрд╛рдкрд╛рд░ рдХреЗ рд▓рд┐рдП рдиреАрдЪреЗ рдЙрддрд░реЛред рдЕрдкрдирд╛ рд╕рдордп рдмрдЪрд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдкреНрд░рддреНрдпреЗрдХ рд╡рд┐рдзрд┐ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рд╡рд┐рд╡рд░рдг рдореЗрдВ рдЬрд╛рдП рдмрд┐рдирд╛ рд╕рд╛рд░ рдХреЛрдб рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВрдЧреЗред рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛрдб рдХрд╛ рд╡рд┐рд╡рд░рдг рдпрд╣рд╛рдВ рдкрд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ: CleanSwiftTests


рджреГрд╢реНрдп рдХреЗ рдкреНрд░рддреНрдпреЗрдХ рдШрдЯрдХ рдХреЗ рд▓рд┐рдП, рд╣рдо рдШрдЯрдХ рдирд┐рд░реНрднрд░рддрд╛ ( рдЯреЗрд╕реНрдЯ рдбрдмрд▓реНрд╕ ) рдХреЗ рд▓рд┐рдП рдкрд░реАрдХреНрд╖рдг рдФрд░ рдкрд░реАрдХреНрд╖рдг рдбрдмрд▓реНрд╕ рдХреЗ рд╕рд╛рде рдПрдХ рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рддреЗ рд╣реИрдВред


рдЗрд╕ рддрд░рд╣ рдХреА рд╕рдВрд░рдЪрдирд╛ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг:



рдкреНрд░рддреНрдпреЗрдХ рдкрд░реАрдХреНрд╖рдг рдлрд╝рд╛рдЗрд▓ рдХреА рд╕рдВрд░рдЪрдирд╛ (рдШрдЯрдХреЛрдВ рдХреЗ рд▓рд┐рдП) рд╕рдорд╛рди рджрд┐рдЦрддреА рд╣реИ рдФрд░ рд▓реЗрдЦрди рдХреЗ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЕрдиреБрдХреНрд░рдо рдХрд╛ рдкрд╛рд▓рди рдХрд░рддреА рд╣реИ:


  • рд╣рдо SUT рдХреЗ рд╕рд╛рде рдПрдХ рдЪрд░ рдШреЛрд╖рд┐рдд рдХрд░рддреЗ рд╣реИрдВ (рдЬрд┐рд╕ рд╡рд╕реНрддреБ рдХрд╛ рд╣рдо рдкрд░реАрдХреНрд╖рдг рдХрд░рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВ) рдФрд░ рдЗрд╕рдХреА рдореБрдЦреНрдп рдирд┐рд░реНрднрд░рддрд╛ рд╡рд╛рд▓реЗ рдЪрд░
  • рд╣рдо рд╕реЗрдЯ ( рдФрд░ ) рдореЗрдВ SUT рдФрд░ рдЙрд╕рдХреА рдирд┐рд░реНрднрд░рддрд╛ рдХреЛ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝ рдХрд░рддреЗ рд╣реИрдВ, рдФрд░ рдлрд┐рд░ рдЙрдиреНрд╣реЗрдВ рдЖрдВрд╕реВ рдореЗрдВ рд╕рд╛рдлрд╝ рдХрд░рддреЗ рд╣реИрдВ ()
  • рдЯреЗрд╕реНрдЯ рдХреЗ рддрд░реАрдХреЗ

рдЬреИрд╕рд╛ рдХрд┐ рд╣рдордиреЗ рд╕рд┐рджреНрдзрд╛рдВрдд рдкрд░ рдЪрд░реНрдЪрд╛ рдХреА, рджреГрд╢реНрдп рдХреЗ рдкреНрд░рддреНрдпреЗрдХ рдШрдЯрдХ рдХреЛ рдЕрд▓рдЧ рд╕реЗ рдкрд░реАрдХреНрд╖рдг рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рд╣рдо рдкрд░реАрдХреНрд╖рдг рдбреБрдкреНрд▓рд┐рдХреЗрдЯ ( рд╕реНрдкрд╛рдИ ) рдХреЛ рдЙрд╕рдХреА рдирд┐рд░реНрднрд░рддрд╛ рдореЗрдВ рдЗрдВрдЬреЗрдХреНрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдЗрд╕ рддрд░рд╣ рд╣рдорд╛рд░реЗ SUT рдХреЗ рддрд░реАрдХреЛрдВ рдХреЗ рд╕рдВрдЪрд╛рд▓рди рдХреА рдирд┐рдЧрд░рд╛рдиреА рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд╣реЛрдо рджреГрд╢реНрдп рдХреЗ рдЗрдВрдЯрд░реЗрдХреНрдЯрд░ рдЙрджрд╛рд╣рд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкрд░реАрдХреНрд╖рдг рд▓рд┐рдЦрдиреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдкрд░ рдХрд░реАрдм рд╕реЗ рдирдЬрд╝рд░ рдбрд╛рд▓рддреЗ рд╣реИрдВред


HomeInteractor рджреЛ рд╡рд╕реНрддреБрдУрдВ рдкрд░ рдирд┐рд░реНрднрд░ рд╣реИ - рдкреНрд░рд╕реНрддреБрддрдХрд░реНрддрд╛ рдФрд░ рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ ред рдХрдХреНрд╖рд╛ рдореЗрдВ рджреЛрдиреЛрдВ рдЪрд░ рдореЗрдВ рдПрдХ рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдкреНрд░рдХрд╛рд░ рд╣реЛрддрд╛ рд╣реИред рдЗрд╕рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рд╣рдо HomePresentationLogic рдФрд░ HomeWorkingLogic рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдХреЗ рддрд╣рдд рд╣рд╕реНрддрд╛рдХреНрд╖рд░рд┐рдд рдЯреЗрд╕реНрдЯ рдбреБрдкреНрд▓рд┐рдХреЗрдЯ рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВ, рдФрд░ рдлрд┐рд░ рдЙрдиреНрд╣реЗрдВ HomeInteractor рдореЗрдВ рдЗрдВрдЬреЗрдХреНрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ ред


final class HomeInteractor: HomeBusinessLogic, HomeDataStore { // MARK: - Public Properties var presenter: HomePresentationLogic? lazy var worker: HomeWorkingLogic = HomeWorker() var users: [User] = [] var selectedUser: User? // MARK: - HomeBusinessLogic func fetchUsers(_ request: HomeModels.FetchUsers.Request) { // ... } func selectUser(_ request: HomeModels.SelectUser.Request) { // ... } 

рд╣рдо рджреЛ рддрд░реАрдХреЛрдВ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░реЗрдВрдЧреЗ:


  • fetchUsers (:) ред рдПрдкреАрдЖрдИ рджреНрд╡рд╛рд░рд╛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреА рд╕реВрдЪреА рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ред рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдХ рдПрдкреАрдЖрдИ рдЕрдиреБрд░реЛрдз рднреЗрдЬрд╛ рдЬрд╛рддрд╛ рд╣реИред
  • рдЪрдпрдирдХрд░реНрддрд╛ (:) рд▓реЛрдб рдХрд┐рдП рдЧрдП рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ ( рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ ) рдХреА рд╕реВрдЪреА рд╕реЗ рд╕рдХреНрд░рд┐рдп рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ ( рдЪрдпрдирд┐рдд рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛) рдХрд╛ рдЪрдпрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ред

рдЗрдВрдЯрд░реЗрдХреНрдЯрд░ рдХреЗ рдкрд░реАрдХреНрд╖рдг рд▓рд┐рдЦрдирд╛ рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдЙрди рдЬрд╛рд╕реВрд╕реЛрдВ рдХреЛ рдмрдирд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдЬреЛ HomePresentationLogic рдФрд░ HomeWorkingLogic рдореЗрдВ рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЗ рдЖрд╣реНрд╡рд╛рди рдХреЛ рдЯреНрд░реИрдХ рдХрд░реЗрдВрдЧреЗред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, 'CleanSwiftTestsTests / Stores / Home / TestDoubles / Spies' рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдореЗрдВ HomePresentationLogicSpy рд╡рд░реНрдЧ рдмрдирд╛рдПрдВ, рдкреНрд░реЛрдЯреЛрдХреЙрд▓ HomePresentationLogic рдкрд░ рд╣рд╕реНрддрд╛рдХреНрд╖рд░ рдХрд░реЗрдВ рдФрд░ рдЗрд╕ рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдХреА рд╡рд┐рдзрд┐ рдХреЛ рд▓рд╛рдЧреВ рдХрд░реЗрдВред


 final class HomePresentationLogicSpy: HomePresentationLogic { // MARK: - Public Properties private(set) var isCalledPresentFetchedUsers = false // MARK: - Public Methods func presentFetchedUsers(_ response: HomeModels.FetchUsers.Response) { isCalledPresentFetchedUsers = true } } 

рдпрд╣рд╛рдВ рд╕рдм рдХреБрдЫ рдмреЗрд╣рдж рдкрд╛рд░рджрд░реНрд╢реА рд╣реИред рдпрджрд┐ PresentFetchedUsers ( HomePresentationLogic ) рд╡рд┐рдзрд┐ рдХреЛ рдХреЙрд▓ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛, рддреЛ рд╣рдо isCalledPresentFetchedUser рдЪрд░ рдХрд╛ рдорд╛рди рд╕рд╣реА рдкрд░ рд╕реЗрдЯ рдХрд░рддреЗ рд╣реИрдВред рдЗрд╕ рдкреНрд░рдХрд╛рд░, рд╣рдо рдпрд╣ рдЯреНрд░реИрдХ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдХреНрдпрд╛ рдЗрд╕ рд╡рд┐рдзрд┐ рдХреЛ рдЗрдВрдЯрд░реЗрдХреНрдЯрд░ рдХреЗ рдкрд░реАрдХреНрд╖рдг рдХреЗ рджреМрд░рд╛рди рдмреБрд▓рд╛рдпрд╛ рдЧрдпрд╛ рдерд╛ред


рдПрдХ рд╣реА рд╕рд┐рджреНрдзрд╛рдВрдд рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП , рд╣реЛрдорд╡рд░реНрдХрд┐рдВрдЧ рд▓реЙрдЬрд┐рдХрд╕рд┐рдХ рдмрдирд╛рдПрдВред рдПрдХ рдЕрдВрддрд░, рд╣рдо рдкреВрд░реНрдгрддрд╛ рдХрд╣рддреЗ рд╣реИрдВ, рдХреНрдпреЛрдВрдХрд┐ рдЗрдВрдЯрд░реЗрдХреНрдЯрд░ рдореЗрдВ рдХреЛрдб рдХрд╛ рд╣рд┐рд╕реНрд╕рд╛ рдЗрд╕ рдкрджреНрдзрддрд┐ рдХреЗ рдмрдВрдж рд╣реЛрдиреЗ рдкрд░ рд▓рдкреЗрдЯрд╛ рдЬрд╛рдПрдЧрд╛ред рд╣реЛрдорд╡рд░реНрдХрд┐рдВрдЧ рд▓реЙрдЬрд┐рдХ рддрд░реАрдХреЗ рдиреЗрдЯрд╡рд░реНрдХ рд░рд┐рдХреНрд╡реЗрд╕реНрдЯ рд╕реЗ рдирд┐рдкрдЯрддреЗ рд╣реИрдВред рд╣рдореЗрдВ рдкрд░реАрдХреНрд╖рдг рдХреЗ рджреМрд░рд╛рди рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдиреЗрдЯрд╡рд░реНрдХ рдЕрдиреБрд░реЛрдзреЛрдВ рд╕реЗ рдмрдЪрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдЗрд╕реЗ рдПрдХ рдЯреЗрд╕реНрдЯ рдЯреЗрдХ рдХреЗ рд╕рд╛рде рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрд┐рдд рдХрд░рддреЗ рд╣реИрдВ, рдЬреЛ рд╡рд┐рдзрд┐ рдХреЙрд▓ рдХреЛ рдЯреНрд░реИрдХ рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЯреЗрдореНрдкрд▓реЗрдЯ рдбреЗрдЯрд╛ рд▓реМрдЯрд╛рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдиреЗрдЯрд╡рд░реНрдХ рдХреЗ рд▓рд┐рдП рдХреЛрдИ рдЕрдиреБрд░реЛрдз рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред


 final class HomeWorkingLogicSpy: HomeWorkingLogic { // MARK: - Public Properties private(set) var isCalledFetchUsers = false let users: [User] = [ User(id: 1, name: "Ivan", username: "ivan91"), User(id: 2, name: "Igor", username: "igor_test") ] // MARK: - Public Methods func fetchUsers(_ completion: @escaping ([User]?) -> Void) { isCalledFetchUsers = true completion(users) } } 

рдЕрдЧрд▓рд╛, рд╣рдо HomeInteractorTests рд╡рд░реНрдЧ рдмрдирд╛рддреЗ рд╣реИрдВ, рдЬрд┐рд╕рдХреЗ рд╕рд╛рде рд╣рдо HomeInteractor рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░реЗрдВрдЧреЗ ред


 final class HomeInteractorTests: XCTestCase { // MARK: - Private Properties private var sut: HomeInteractor! private var worker: HomeWorkingLogicSpy! private var presenter: HomePresentationLogicSpy! // MARK: - Lifecycle override func setUp() { super.setUp() let homeInteractor = HomeInteractor() let homeWorker = HomeWorkingLogicSpy() let homePresenter = HomePresentationLogicSpy() homeInteractor.worker = homeWorker homeInteractor.presenter = homePresenter sut = homeInteractor worker = homeWorker presenter = homePresenter } override func tearDown() { sut = nil worker = nil presenter = nil super.tearDown() } // MARK: - Public Methods func testFetchUsers() { // ... } func testSelectUser() { // ... } } 

рд╣рдо рддреАрди рдореБрдЦреНрдп рдЪрд░ рдЗрдВрдЧрд┐рдд рдХрд░рддреЗ рд╣реИрдВ - sut , рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рдФрд░ рдкреНрд░рд╕реНрддреБрддрдХрд░реНрддрд╛ ред


рд╕реЗрдЯрдЕрдк () рдореЗрдВ, рдЖрд╡рд╢реНрдпрдХ рд╡рд╕реНрддреБрдУрдВ рдХреЛ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝ рдХрд░реЗрдВ, рдЗрдВрдЯрд░рдПрдХреНрдЯрд░ рдореЗрдВ рдирд┐рд░реНрднрд░рддрд╛ рдХреЛ рдЗрдВрдЬреЗрдХреНрдЯ рдХрд░реЗрдВ рдФрд░ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рдХреНрд▓рд╛рд╕ рд╡реЗрд░рд┐рдПрдмрд▓реНрд╕ рдореЗрдВ рдЕрд╕рд╛рдЗрди рдХрд░реЗрдВред
рдЯрд┐рдпрд░рдбрд╛рдЙрди () рдореЗрдВ, рд╣рдо рдкреНрд░рдпреЛрдЧ рдХреА рд╢реБрджреНрдзрддрд╛ рдХреЗ рд▓рд┐рдП рд╡рд░реНрдЧ рдЪрд░ рд╕реНрдкрд╖реНрдЯ рдХрд░рддреЗ рд╣реИрдВред


рд╕реЗрдЯрдЕрдк () рд╡рд┐рдзрд┐ рдХреЛ рдкрд░реАрдХреНрд╖рдг рд╡рд┐рдзрд┐ рд╢реБрд░реВ рд╣реЛрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП testFetchUsers () , рдФрд░ tearDown () рдЬрдм рдЗрд╕ рд╡рд┐рдзрд┐ рдиреЗ рдЕрдкрдирд╛ рдХрд╛рдо рдкреВрд░рд╛ рдХрд┐рдпрд╛ рд╣реИред рдЗрд╕ рдкреНрд░рдХрд╛рд░, рд╣рдо рдкреНрд░рддреНрдпреЗрдХ рдкрд░реАрдХреНрд╖рдг рд╡рд┐рдзрд┐ рдХреЛ рдЪрд▓рд╛рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдкрд░реАрдХреНрд╖рдг рдСрдмреНрдЬреЗрдХреНрдЯ ( sut ) рдХреЛ рдлрд┐рд░ рд╕реЗ рдмрдирд╛рддреЗ рд╣реИрдВред


рдЗрд╕рдХреЗ рдмрд╛рдж рдкрд░реАрдХреНрд╖рдг рдХреЗ рддрд░реАрдХреЗ рд╕реНрд╡рдпрдВ рд╣реИрдВред рд╕рдВрд░рдЪрдирд╛ рдХреЛ 3 рдореБрдЦреНрдп рддрд╛рд░реНрдХрд┐рдХ рдмреНрд▓реЙрдХреЛрдВ рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ - рдЖрд╡рд╢реНрдпрдХ рд╡рд╕реНрддреБрдУрдВ рдХрд╛ рдирд┐рд░реНрдорд╛рдг, SUT рдореЗрдВ рдкрд░реАрдХреНрд╖рдг рд╡рд┐рдзрд┐ рдХрд╛ рд╢реБрднрд╛рд░рдВрдн рдФрд░ рдкрд░рд┐рдгрд╛рдореЛрдВ рдХрд╛ рд╕рддреНрдпрд╛рдкрдиред рдиреАрдЪреЗ рджрд┐рдП рдЧрдП рдЙрджрд╛рд╣рд░рдг рдореЗрдВ, рд╣рдо рдПрдХ рдЕрдиреБрд░реЛрдз рдмрдирд╛рддреЗ рд╣реИрдВ (рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдЗрд╕рдХрд╛ рдХреЛрдИ рдкреИрд░рд╛рдореАрдЯрд░ рдирд╣реАрдВ рд╣реИ), fetchUsers (:) рдЗрдВрдЯрд░реЗрдХреНрдЯрд░ рд╡рд┐рдзрд┐ рдХреЛ рдЪрд▓рд╛рдПрдБ, рдФрд░ рдлрд┐рд░ рдЬрд╛рдВрдЪреЗрдВ рдХрд┐ рдХреНрдпрд╛ HomeWorkingLogicSpy рдФрд░ HomeresresentationLogicSpy рдореЗрдВ рдЖрд╡рд╢реНрдпрдХ рддрд░реАрдХреЛрдВ рдХреЛ рдмреБрд▓рд╛рдпрд╛ рдЧрдпрд╛ рд╣реИред рд╣рдо рдпрд╣ рднреА рдЬрд╛рдВрдЪрддреЗ рд╣реИрдВ рдХрд┐ рдХреНрдпрд╛ рдЗрдВрдЯрд░рдПрдХреНрдЯрд░ рдиреЗ рд╡рд░реНрдХрд░ рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдбреЗрдЯрд╛ рдХреЛ рдЕрдкрдиреЗ рдбреЗрдЯрд╛рд╕реНрдЯреЛрд░ рдореЗрдВ рд╕рд╣реЗрдЬрд╛ рд╣реИ рдпрд╛ рдирд╣реАрдВред


 func testFetchUsers() { let request = HomeModels.FetchUsers.Request() sut.fetchUsers(request) XCTAssertTrue(worker.isCalledFetchUsers, "Not started worker.fetchUsers(:)") XCTAssertTrue(presenter.isCalledPresentFetchedUsers, "Not started presenter.presentFetchedUsers(:)") XCTAssertEqual(sut.users.count, worker.users.count) } 

рд╣рдо рдПрдХ рд╕рдорд╛рди рд╕рдВрд░рдЪрдирд╛ рджреНрд╡рд╛рд░рд╛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреА рдкрд╕рдВрдж рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░реЗрдВрдЧреЗред рд╣рдо рд╡реИрд░рд┐рдПрдмрд▓ рдкреНрд░рддреНрдпрд╛рд╢рд╛ рдХреА рдШреЛрд╖рдгрд╛ рдХрд░рддреЗ рд╣реИрдВред рдореИрдВ рдФрд░ рдкреНрд░рддреНрдпрд╛рд╢рд╛рдирд╛рдо , рдЬрд┐рд╕рдХреЗ рджреНрд╡рд╛рд░рд╛ рд╣рдо рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рдЪрдпрди рдХреЗ рдкрд░рд┐рдгрд╛рдо рдХреА рддреБрд▓рдирд╛ рдХрд░реЗрдВрдЧреЗред рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЪрд░ рдЙрди рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреА рдПрдХ рдкрд░реАрдХреНрд╖рдг рд╕реВрдЪреА рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рддрд╛ рд╣реИ, рдЬрд┐рдиреНрд╣реЗрдВ рд╣рдо рдЗрдВрдЯрд░рдПрдХреНрдЯрд░ рдХреЛ рд╕реМрдВрдкрддреЗ рд╣реИрдВред рдХреНрдпреЛрдВрдХрд┐ рдкрд░реАрдХреНрд╖рдг рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ рдПрдХ-рджреВрд╕рд░реЗ рд╕реЗ рд╕реНрд╡рддрдВрддреНрд░ рд░реВрдк рд╕реЗ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░ рдЖрдВрд╕реВ рдореЗрдВ () рд╣рдо рдбреЗрдЯрд╛ рдХреЛ рд╢реВрдиреНрдп рдХрд░рддреЗ рд╣реИрдВ, рдлрд┐рд░ рдЗрдВрдЯрд░рдПрдХреНрдЯрд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреА рд╕реВрдЪреА рдЦрд╛рд▓реА рд╣реИ рдФрд░ рд╣рдореЗрдВ рдЗрд╕реЗ рдХреБрдЫ рдХреЗ рд╕рд╛рде рднрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдФрд░ рдлрд┐рд░ рд╣рдо рдпрд╣ рдЬрд╛рдВрдЪрддреЗ рд╣реИрдВ рдХрд┐ sut.selectUser (:) , рдФрд░ рдХреНрдпрд╛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд╕рд╣реА рд╣реИ, рдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж рдбреЗрдЯрд╛рд╕реНрдЯреЛрд░рд╕реНрдЯреЛрд░ рдореЗрдВ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рд╕реМрдВрдкрд╛ рдЧрдпрд╛ рдерд╛ рдпрд╛ рдирд╣реАрдВред


 func testSelectUser() { let expectationId = 2 let expectationName = "Vasya" let users = [ User(id: 1, name: "Ivan", username: "ivan"), User(id: 2, name: "Vasya", username: "vasya91"), User(id: 3, name: "Maria", username: "maria_love") ] let request = HomeModels.SelectUser.Request(index: 1) sut.users = users sut.selectUser(request) XCTAssertNotNil(sut.selectedUser, "User not selected") XCTAssertEqual(sut.selectedUser?.id, expectationId) XCTAssertEqual(sut.selectedUser?.name, expectationName) } 

рдкрд░реАрдХреНрд╖рдг рдкреНрд░рд╕реНрддреБрддрдХрд░реНрддрд╛ рдФрд░ ViewController'a рдПрдХ рд╣реА рд╕рд┐рджреНрдзрд╛рдВрдд рдкрд░ рд╣реЛрддрд╛ рд╣реИ, рдЬрд┐рд╕рдореЗрдВ рдиреНрдпреВрдирддрдо рдЕрдВрддрд░ рд╣реЛрддрд╛ рд╣реИред рдПрдХ рдЕрдВрддрд░ рдпрд╣ рд╣реИ рдХрд┐ ViewController рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП , рдЖрдкрдХреЛ рдПрдХ UIWindow рдмрдирд╛рдиреЗ рдФрд░ setUp () рдореЗрдВ рд╕реНрдЯреЛрд░реАрдмреЛрд░реНрдб рд╕реЗ рдирд┐рдпрдВрддреНрд░рдХ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА, рд╕рд╛рде рд╣реА рдЯреЗрдмрд▓ рдФрд░ рд╕рдВрдЧреНрд░рд╣ рдкрд░ рд╕реНрдкрд╛рдИ рдСрдмреНрдЬреЗрдХреНрдЯ рднреА рдмрдирд╛рдПрдВрдЧреЗред рд▓реЗрдХрд┐рди рдпреЗ рдмрд╛рд░реАрдХрд┐рдпрд╛рдВ рдЬрд░реВрд░рддреЛрдВ рд╕реЗ рднрд┐рдиреНрди рд╣реЛрддреА рд╣реИрдВред


рдкреВрд░реНрдгрддрд╛ рдХреЗ рд▓рд┐рдП, рдореЗрд░рд╛ рд╕реБрдЭрд╛рд╡ рд╣реИ рдХрд┐ рдЖрдк рд▓реЗрдЦ рдХреЗ рдЕрдВрдд рдореЗрдВ рд▓рд┐рдВрдХ рджреНрд╡рд╛рд░рд╛ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЗ рд╕рд╛рде рдЦреБрдж рдХреЛ рдкрд░рд┐рдЪрд┐рдд рдХрд░реЗрдВред


рдирд┐рд╖реНрдХрд░реНрд╖


рд╣рдордиреЗ рд╕реНрд╡рдЪреНрдЫ рд╕реНрд╡рд┐рдлреНрдЯ рд╡рд╛рд╕реНрддреБрдХрд▓рд╛ рдкрд░ рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХреЗ рдкрд░реАрдХреНрд╖рдг рдХреЗ рдореВрд▓ рд╕рд┐рджреНрдзрд╛рдВрддреЛрдВ рдХреЛ рдХрд╡рд░ рдХрд┐рдпрд╛ рд╣реИред рдпрд╣ рдЕрдиреНрдп рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░ рдкрд░ рдкрд░реАрдХреНрд╖рдг рдкрд░рд┐рдпреЛрдЬрдирд╛рдУрдВ, рд╕рднреА рд╕рдорд╛рди рдкрд░реАрдХреНрд╖рдг рдбрдмрд▓реНрд╕, рдЗрдВрдЬреЗрдХреНрд╢рди рдФрд░ рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рд╕реЗ рдореМрд▓рд┐рдХ рд░реВрдк рд╕реЗ рдордЬрдмреВрдд рдЕрдВрддрд░ рдирд╣реАрдВ рд╣реИред рдореБрдЦреНрдп рдмрд╛рдд рдпрд╣ рдирд╣реАрдВ рд╣реИ рдХрд┐ рдкреНрд░рддреНрдпреЗрдХ рд╡реАрдЖрдИрдкреА рдЪрдХреНрд░ рдореЗрдВ рдПрдХ (рдФрд░ рдХреЗрд╡рд▓ рдПрдХ!) рдЬрд┐рдореНрдореЗрджрд╛рд░реА рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдПред рдЗрд╕рд╕реЗ рдХреЛрдб рдХреНрд▓реАрдирд░ рдФрд░ рдкрд░реАрдХреНрд╖рдг рдЕрдзрд┐рдХ рд╕реНрдкрд╖реНрдЯ рд╣реЛ рдЬрд╛рдПрдВрдЧреЗред


рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЗ рд▓рд┐рдП рд▓рд┐рдВрдХ: CleanSwiftTests
рдПрдХ рд▓реЗрдЦ рд▓рд┐рдЦрдиреЗ рдореЗрдВ рдорджрдж: рдмрд╛рд╕реНрдЯрд┐рдпрди


рд▓реЗрдЦреЛрдВ рдХреА рд╢реНрд░реГрдВрдЦрд▓рд╛


  1. рд╕реНрд╡рдЪреНрдЫ рд╕реНрд╡рд┐рдлреНрдЯ рд╡рд╛рд╕реНрддреБрдХрд▓рд╛ рдЕрд╡рд▓реЛрдХрди
  2. рд╕реНрд╡рдЪреНрдЫ рд╕реНрд╡рд┐рдлреНрдЯ рд╡рд╛рд╕реНрддреБрдХрд▓рд╛ рдореЗрдВ рд░рд╛рдЙрдЯрд░ рдФрд░ рдбреЗрдЯрд╛ рдкрд╛рд╕рд┐рдВрдЧ
  3. рдХреНрд▓реАрди рд╕реНрд╡рд┐рдлреНрдЯ рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░ рдореЗрдВ рд╢реНрд░рдорд┐рдХ
  4. рд╕реНрд╡рдЪреНрдЫ рд╕реНрд╡рд┐рдлреНрдЯ рд╡рд╛рд╕реНрддреБрдХрд▓рд╛ рдореЗрдВ рдЗрдХрд╛рдИ рдкрд░реАрдХреНрд╖рдг (рдЖрдк рдпрд╣рд╛рдВ рд╣реИрдВ)
  5. рдПрдХ рд╕рд░рд▓ рдСрдирд▓рд╛рдЗрди рд╕реНрдЯреЛрд░ рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░ рдХреНрд▓реАрди рд╕реНрд╡рд┐рдлреНрдЯ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг

Source: https://habr.com/ru/post/hi483882/


All Articles