Phpunit between different apis

Hello,
I have some separate apis created in Slim and now I need to unite them to use them together.

I am creating the integration tests to test that they work correctly.

I have the following test, the first thing it does is upload a file to one of the APIs and with the result I call the API where this test is and store the route that the first request returned me

    public function testCreateWithImage()
    {
        $file_original = __DIR__ . "/../fixtures/files/pixel.jpg";
        $file_copy = __DIR__ . "/../fixtures/files/pixel_copy.jpg";
        copy($file_original, $file_copy);

        $uploadedFile = new UploadedFile(
            $file_copy,
            "pixel.jpg",
            'image/jpeg',
            filesize($file_copy),
        );

        $uploadedFiles["files"][] = $uploadedFile;


        $request = $this->createRequest('POST', '/v1/ficheros/upload/public', "path=seccion", ['HTTP_ACCEPT' => 'application/json'], self::$cookies, host: (string) getenv('APACHE_DOMAIN_FILES'));
        $request = $request->withHeader('Content-Type', 'multipart/form-data');
        $request = $request->withUploadedFiles($uploadedFiles);
        $response = $this->getAppInstance()->handle($request);

        $result = (string) $response->getBody();
        $result = json_decode($result);
        
        $this->assertEquals(201, $response->getStatusCode());

        $req = $this->createRequest('POST', '/v1/crm/web/secciones', '', ['HTTP_ACCEPT' => 'application/json'], self::$cookies);
        $request = $req->withParsedBody($this->params_seccion);
        $response = $this->getAppInstance()->handle($request);

        $result = (string) $response->getBody();

        $this->assertEquals(201, $response->getStatusCode());
        $this->assertStringContainsString('id', $result);
        $this->assertStringNotContainsString('error', $result);
    }

The problem I have is that the first request returns a 404 error and therefore the image is not uploaded.

    protected function createRequest(
        string $method,
        string $path,
        string $query = '',
        array $headers = ['HTTP_ACCEPT' => 'application/json'],
        array $cookies = [],
        array $serverParams = [],
        array $uploadedFiles = [],
        string $scheme = 'http',
        string $host = 'localhost',
    ) {
        $uri = new Uri($scheme, $host, 80, $path, $query);

        $handle = fopen('php://temp', 'w+');
        $stream = (new StreamFactory())->createStreamFromResource($handle);

        $h = new Headers();
        foreach ($headers as $name => $value) {
            $h->addHeader($name, $value);
        }

        return new SlimRequest($method, $uri, $h, $cookies, $serverParams, $stream, $uploadedFiles);
    }

If I print the uri that I pass to SlimRequest, it’s the same configuration as in postman if it works.

class Slim\Psr7\Uri#1021 (8) {
  protected $scheme =>
  string(4) "http"
  protected $user =>
  string(0) ""
  protected $password =>
  string(0) ""
  protected $host =>
  string(26) "files.green.fitcloud.local"
  protected $port =>
  int(80)
  protected $path =>
  string(26) "/v1/ficheros/upload/public"
  protected $query =>
  string(12) "path=seccion"
  protected $fragment =>
  string(0) ""
}

Some idea? Is it better to make the requests directly through curl since they are different APIs?

Thanks for your time

Have you checked the url path? The public/ directory should be the DocumentRoot and not be in the url.

that url is like this because it may be uploaded to a private area so the url would be the following in the other case

class Slim\Psr7\Uri#1021 (8) {
  protected $scheme =>
  string(4) "http"
  protected $user =>
  string(0) ""
  protected $password =>
  string(0) ""
  protected $host =>
  string(26) "files.green.fitcloud.local"
  protected $port =>
  int(80)
  protected $path =>
  string(26) "/v1/ficheros/upload/private"
  protected $query =>
  string(12) "path=seccion"
  protected $fragment =>
  string(0) ""
}

It is not the documentroot

I would try to write a new test without any uploads etc. just to see if the routing works.

If I do the tests without uploading files between the different APIs, it works perfectly for me.

The files API test in your API works.

But now I need to do combined testing as if it were microservices.

If routing works, the question for me is then, why do you get an 404 (not found) error when you upload something?

I finally solved the problem using Guzzle to upload the file to the service that is on another domain and then continue with the normal tests.

public function testCreateWithImage()
    {
        $apifiles = 'http://' . (string) getenv('APACHE_DOMAIN_FILES');
        $clientHttp = new Client(['base_uri' => $apifiles, 'timeout' => 2.0, 'verify' => false]);
 
        $cookie_data = explode(';', self::$cookies[(string) getenv('SESSION_NAME')]);
        $cookieJar = CookieJar::fromArray([
            (string) getenv('SESSION_NAME') => $cookie_data[0],
        ], (string) getenv('SESSION_DOMAIN'));
        
        $datafile = array(
            'cookies' => $cookieJar,
            'multipart' => [
                [
                    'name' => 'files[]',
                    'contents' => fopen(__DIR__ . "/../fixtures/files/pixel.jpg", 'r'),
                    'filename' => 'pixel_test.jpg'
                ]
            ]
        );
        $response = $clientHttp->request('POST', '/v1/ficheros/upload/public?path=seccion', $datafile);


        $result = (string) $response->getBody();

        $result = json_decode($result);
        $this->assertEquals(StatusCodeInterface::STATUS_CREATED, $response->getStatusCode());

        $this->assertEquals('pixel_test.jpg', $result[0]->name);
        $this->assertEquals('image/jpeg', $result[0]->mime);
        $this->assertEquals(1250, $result[0]->size);
        $this->assertEquals('34a573f1dfa0dcfe3042a92d3bde0b31', $result[0]->md5_file);

        $params = $this->params_seccion;
        $params['imagenes']['imagen'] = "${apifiles}/v1/public/seccion/{$result[0]->name}";

        $req = $this->createRequest('POST', '/v1/crm/web/secciones', '', ['HTTP_ACCEPT' => 'application/json'], self::$cookies);
        $request = $req->withParsedBody($params);
        $response = $this->getAppInstance()->handle($request);

        $result = (string) $response->getBody();

        $this->assertEquals(201, $response->getStatusCode());
        $this->assertStringContainsString('id', $result);
        $this->assertStringNotContainsString('error', $result);
    }

I’m sure it works without Guzzle, but I’m happy you found a working solution.