ImageField Test In View

I'm trying to post an Image on 'accounts/profile_edit' url in one of my tests. I have a Profile model which resizes images bigger than (225, 255) and this is the functionality I want to test. I read how to unit test file upload in django but I can't get client.post to work with image. What is the problem?

class TestProfileEditView(TestCase):
    # other tests...

    def test_profile_picture_resize(self):
        self.client.force_login(user=self.user)
        image = Image.new('RGB', (500, 500), (255, 255, 255))
        image_location = f'{settings.MEDIA_ROOT}/TestProfilePictureResize.png'
        image.save(image_location)

        with open(image_location ,'rb') as f:
            response = self.client.post(reverse('profile-edit-view'), {'picture': f})
            profile = Profile.objects.get(user=self.user.id)
            picture_path = profile.picture # falsely returns default picture location
            self.assertEqual(picture_path,
                     /media/profile_pictures/TestProfilePictureResize.png)
            self.assertTemplateUsed(response, 'user/profile.html') # returns False
            

views.py :

@login_required
def profile_edit(request):
    if request.method == 'POST':
        user_form = UserEditForm(request.POST, instance=request.user)
        profile_form = ProfileEditForm(
            request.POST, request.FILES, instance=request.user.profile)
        if user_form.is_valid() and profile_form.is_valid():
            user_form.save()
            profile_form.save()
            messages.success(request, f'Profile Edited Successfully.')
            return redirect(reverse('profile-view'), request.user)
    else:
        user_form = UserEditForm(instance=request.user)
        profile_form = ProfileEditForm(instance=request.user.profile)
    context = {
        'user_form': user_form,
        'profile_form': profile_form
    }
    return render(request, 'user/profile_edit.html', context)

models.py :

class User(AbstractUser):
    email = models.EmailField(unique=True, blank=False, null=False)
    first_name = models.CharField(max_length=50, blank=False, null=False)
    last_name = models.CharField(max_length=50, blank=False, null=False)

    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = ["first_name", "last_name"]

    def __str__(self):
        return f"{self.first_name} {self.last_name}"


    class Profile(models.Model):
        user = models.OneToOneField(User, on_delete=models.CASCADE)
        picture = models.ImageField(
            default=f"default_profile_picture.png",
            upload_to="profile_pictures"
        )

        def save(self, *args, **kwargs):
            super().save(*args, **kwargs)
            with Image.open(self.picture.path) as image:
                if image.height > 225 or image.width > 225:
                    size = (225, 225)
                    image.resize(size, Image.ANTIALIAS).save(self.picture.path)
    
        def __str__(self):
            return f"{self.user.first_name} {self.user.last_name} Profile"

I found the answer. If you have two ModelForms in a view, since they are already filled with data you should keep an eye on both of them. you can not pass data to one of them and do not send any data to another if the latter has any field that is required. In my case since I did not pass any data to UserEditForm, is_valid() method returned False and based on logic of the views the user_form.save() and profile_form.save() never excecuted. solution (passing valid data to user_form):

with open(test_image_location,'rb') as f:
    response = self.client.post(reverse('profile-edit-view'), {
                'email':'ProfileEditViewTest@google.com',
                'first_name':'first',
                'last_name':'last',
                'picture': f }, follow=True)
Back to Top