Search code examples
symfonyservicedoctrine-ormphpunitsymfony4

How to test service function without connecting on database


I'm turning again on you guys, because I spend my fair share of hours on this "task" and I still can't figure out how to test my service method, without my function connection on database (I have to mock repository functions)

This is my service function

public function getInfo($history, $name)
{
    $requestRepository = $this->em->getRepository(Request::class);

    if ($history) {
        $requests = [];
        foreach ($requestRepository->getRequestsByName($name) as $request) {
            $requests[] = $requestRepository->transform($request);
        }
        return $requests;
    } else {
        $request = $requestRepository->getCompletedRequestByName($name);
        if (!is_null($request)) {
            return $requestRepository->transform($request);
        } else {
            return null;
        }
    }
}

And this is my test

public function testGetInfo()
{
    /* This returns errors, because it tries to connect to DATABASE, but I don't wan't that, that's why I figure out I need to mock this
    $requestManager = new RequestManager($this->entityManager);
    $test = $requestManager->getInfo('histroy', 'antrax.com');
    */

    $requestManager = $this->getMockBuilder(RequestManager::class)->disableOriginalConstructor()->setMethods(['getInfo'])
        ->getMock();

    // And rest of this are just my FAILED attempts to figure out, how to test my methods
    $queryBuilder = $this->getMockBuilder(RequestRepository::class)->disableOriginalConstructor()
        ->setMethods(['getInfo'])->getMock();

    $test = $queryBuilder->method('getInfo')->willReturnSelf();

    $queryBuilder->method('getInfo')->willReturnCallback(function ($field, $value) use ($queryBuilder, $test){
        if ($field == 'newStatus') {
            $this->assertSame('EXPIRED', $value);
        }
        return $queryBuilder;
    });
}

Can some one please help me how to write a test for my method getInfo so it will have 100% cover. If you need any additional informations, please let me know and I will provide. Thank you!


Solution

  • This is an answer to my problem

    public function testGetInfo()
    {
        $mockEntity = $this->mockEntityManager;
    
        $name = 'antrax.com';
        $requestMock = new RequestEntity();
        $transformedRequest = [
            'id' => 1
        ];
    
        $requestRepo = $this->getMockBuilder(RequestRepository::class)->disableOriginalConstructor()
        ->setMethods(['getRequestsByName', 'transform', 'getCompletedRequestByName'])->getMock();
    
        $requestRepo->method('getRequestsByName')->willReturnCallback(function ($passedName) use ($name, $requestMock) {
            $this->assertSame($name, $passedName);
    
            return [$requestMock, $requestMock];
        });
    
        $requestRepo->method('transform')->willReturnCallback(function ($request) use ($requestMock, $transformedRequest) {
            $this->assertSame($requestMock, $request);
    
            return $transformedRequest;
        });
    
        $i = 0;
        $requestRepo->method('getCompletedRequestByName')->willReturnCallback(function ($passedName) use ($name, $requestMock, &$i) {
            $this->assertSame($name, $passedName);
            if ($i == 0) {
                $i+=1;
                return null;
            } else {
                return $requestMock;
            }
        });
    
        $mockEntity->method('getRepository')->willReturnCallback(function ($requestClass) use ($requestRepo) {
            $this->assertSame(RequestEntity::class, $requestClass);
    
            return $requestRepo;
        });
    
        $requestManager = new RequestManager($mockEntity);
        $this->assertSame([$transformedRequest, $transformedRequest], $requestManager->getInfo(true, $name));
    
        $this->assertNull($requestManager->getInfo(false, $name));
    
        $this->assertSame($transformedRequest, $requestManager->getInfo(false, $name));
    }