PHP unit test to confirm that a validator is being called correctly

I have a Responder class whose prepare method takes an entity, checks it with a validator, and returns a response or errorResponse based on the results of validator.

class CreatorResponder implements ResponderInterface {     private $  validator;     private $  repositoryFactory;     private $  httpResponseFactory;      public function __construct(         ValidatorInterface $  validator,         RepositoryFactoryInterface $  repositoryFactory,         HttpResponseFactoryInterface $  httpResponseFactory     ){         $  this->validator = $  validator;         $  this->repositoryFactory = $  repositoryFactory;         $  this->httpResponseFactory = $  httpResponseFactory;     }      public function prepare(AbstractEntity $  entity) : SimpleHttpResponseInterface     {         $  validatorResponse = $  this->validator->validate($  entity);         if ($  validatorResponse->isValid()) {              $  repository = $  this->repositoryFactory->create($  entity);             $  repository->persist($  entity);              return $  this->getSuccessResponse($  entity);         }         return $  this->getFailureResponse($  validatorResponse->getErrors());     }      protected function getSuccessResponse(AbstractEntity $  entity): SimpleHttpResponseInterface     {         $  response = $  this->httpResponseFactory->create(200, $  entity);         return $  response;     }      protected function getFailureResponse(array $  errors): SimpleHttpResponseInterface     {         $  response = $  this->httpResponseFactory->create(422, $  errors);         return $  response;     } } 

The code is pretty simple, but its unit test is just pain in the ass. It is too big, hard to read, hard to maintain. That is because of mocking. Even repositoryFactory class is mocked, and it return a repository that is again mocked, so a mock is returning a mock.

class CreatorResponderTest extends ResponderTestBase {     public function testPrepare_withValid() : void     {         $  validator = $  this->getValidator(             true,             [$  this->responseContent]         );         $  repositoryFactory = $  this->getRepositoryFactory();          $  entity = $  this->getEntity();          $  httpResponseFactory = $  this->getHttpResponseFactory(             $  this->validStatusCode,             $  this->responseContent         );          $  responder = new CreatorResponder($  validator, $  repositoryFactory, $  httpResponseFactory);         $  response = $  responder->prepare($  entity);          $  this->assertInstanceOf(SimpleHttpResponseInterface::class, $  response);         $  this->assertEquals($  this->validStatusCode, $  response->getStatusCode());         $  this->assertEquals(             $  this->responseContent,             $  response->getContent()         );     }       public function testPrepare_withInvalid() : void     {         $  validator = $  this->getValidator(             false,             [$  this->responseContent]         );         $  repositoryFactory = $  this->getRepositoryFactory();         $  entity = $  this->getEntity();          $  httpResponseFactory = $  this->getHttpResponseFactory(             $  this->invalidStatusCode,             $  this->responseContent         );          $  responder = new CreatorResponder($  validator, $  repositoryFactory, $  httpResponseFactory);         $  response = $  responder->prepare($  entity);          $  this->assertInstanceOf(SimpleHttpResponseInterface::class, $  response);         $  this->assertEquals($  this->invalidStatusCode, $  response->getStatusCode());         $  this->assertEquals(             $  this->responseContent,             $  response->getContent()         );     } } 

The base class of tests actually creates all these mocks.

class ResponderTestBase extends TestCase {     protected $  responseContent = 'some random content string!';     protected $  validStatusCode = 200;     protected $  invalidStatusCode = 422;      protected function getValidator(bool $  isValid, $  content)     {         $  validatorWithValidResponseStub = $  this->createMock(             ValidatorInterface::class         );          $  validatorResponse = new ValidatorResponse($  isValid, $  content);          $  validatorWithValidResponseStub->method('validate')             ->willReturn($  validatorResponse);          return $  validatorWithValidResponseStub;      }      protected function getEntity()     {         $  entityStub = $  this->createMock(             AbstractEntity::class         );          $  entityStub->method('getId')             ->willReturn(1);          return $  entityStub;     }      protected function getRepositoryFactory()     {         $  repositoryMock = $  this->createMock(             RepositoryFactoryInterface::class         );          $  repositoryMock->expects($  this->any())             ->method('persist')             ->with($  this->isInstanceOf(AbstractEntity::class));          return $  repositoryMock;     }      protected function getRepository()     {         $  repositoryMock = $  this->createMock(             RepositoryInterface::class         );          $  repositoryMock->expects($  this->any())             ->method('persist')             ->with($  this->isInstanceOf(AbstractEntity::class));          return $  repositoryMock;     }      protected function getHttpResponseFactory(int $  httpStatusCode, $  content)     {         $  httpResponseFactoryStub = $  this->createMock(             HttpResponseFactoryInterface::class         );          if (!is_string($  content)) {             $  content = json_encode($  content);         }          $  httpResponseFactoryStub->method('create')             ->willReturn($  this->getSimpleHttpResponse($  httpStatusCode, $  content));          return $  httpResponseFactoryStub;     }      protected function getSimpleHttpResponse(int $  httpStatusCode, $  content)     {         return new SimpleHttpResponse($  httpStatusCode, $  content);     } } 

This whole problem is all because of mocking. Everytime I touch something in the class, I have to come to test and find the thing that disturbed it and it takes a lot more time to deal with this test. I think if I just don’t mock repositoryFactory and httpResponseFactory here, a lot of my problem will be solved. I will not have mocks returning mocks. My unit tests will get more focused on behaviour instead of implementation. But I will lose isolation and it will turn into an integrated test. What is your take on that and how can I improve it?

I also tried not mocking repositoryFactory, but to create its instance, I will to bring in EntityManager that goes in repositoryFactory constructor. Again, this will need either mocking or accessing service container. So, not mocking is not good either. I think my design is bad. What’s better?