Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

casenjo's avatar

Testing image upload to API endpoint

I'm trying to write a unit test to verify image uploads but I'm not able to get it to go beyond the request validation itself. When I send a request with Postman (using a POST and _method=put) with a file I get the proper functionality (error on non-image file, success on image). When I run the test it fails because the validator keeps returns the following error messages:

{"avatar":["The avatar may not be greater than 3072 kilobytes.","Your avatar must be a valid image file to continue."]}

My validation rule is:

'avatar' => 'image|max:3072',

My unit test code is:

    public function testUpdateAvatar()
    {
        $this->loginUser(); // Obtain JWT to include in $this->headers
        $path = public_path().'/images/avatar.png'; // Static image in current file-system, smaller than 3072 Kb
        TestCase::assertFileExists($path);
        $finfo = finfo_open(FILEINFO_MIME_TYPE);
        $mime = finfo_file($finfo, $path);
        $uploadFile = new \Symfony\Component\HttpFoundation\File\UploadedFile($path, null, $mime, null, null, true);
        $this->profileData['avatar'] = $uploadFile;

        $this->json('PUT', $this->apiUri.'/users', $this->profileData, $this->headers)
              ->seeJsonEquals(['message' => ['success']]);
    }

I know the image file exists and I've verified its MIME type so I'm guessing there's something wrong with the json() call that I'm making, but I'm not sure what it is...

Update: I removed the request validator class from the controller action's signature and replaced it with a normal Request instead, and then I dumped the request. The request itself does indeed contain the file too.

...
+files: Symfony\Component\HttpFoundation\FileBag {#699
    #parameters: array:1 [
      "avatar" => Symfony\Component\HttpFoundation\File\UploadedFile {#698
        -test: true
        -originalName: ""
        -mimeType: "image/png"
        -size: null
        -error: 0
        path: "/home/vagrant/Code/spoil-app/public/images"
        filename: "avatar_generic_o.png"
        basename: "avatar_generic_o.png"
        pathname: "/home/vagrant/Code/spoil-app/public/images/avatar_generic_o.png"
        extension: "png"
        realPath: "/home/vagrant/Code/spoil-app/public/images/avatar_generic_o.png"
        aTime: 2016-06-07 23:31:53
        mTime: 2016-05-26 18:30:49
        cTime: 2016-05-26 18:30:49
        inode: 305012
        size: 15801
        perms: 0100644
        owner: 900
        group: 900
        type: "file"
        writable: true
        readable: true
        executable: false
        file: true
        dir: false
        link: false
      }
    ]
  }
...
 +headers: Symfony\Component\HttpFoundation\HeaderBag {#700
    #headers: array:8 [
      "host" => array:1 [
        0 => "localhost"
      ]
      "user-agent" => array:1 [
        0 => "Symfony/3.X"
      ]
      "accept" => array:1 [
        0 => "application/json"
      ]
      "accept-language" => array:1 [
        0 => "en-us,en;q=0.5"
      ]
      "accept-charset" => array:1 [
        0 => "ISO-8859-1,utf-8;q=0.7,*;q=0.7"
      ]
      "content-length" => array:1 [
        0 => 115
      ]
      "content-type" => array:1 [
        0 => "application/json"
      ]
      "authorization" => array:1 [
        0 => "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjIwODIsImlzcyI6Imh0dHA6XC9cL2xvY2FsaG9zdCIsImlhdCI6MTQ2NTM0MTI3NSwiZXhwIjoxNDY1MzQ0ODc1LCJuYmYiOjE0NjUzNDEyNzUsImp0aSI6Ijg4ZTViYTBmNjJmNDc1NDFkNTc1NWU5NjkyZDllYWE1In0.A1GgKgpQ9qvVipLBEoRkANW1GIKcHt3qxhuo2M_HRqo"
      ]
    ]
...
0 likes
0 replies

Please or to participate in this conversation.