About testing and `client.force_login()`

I cannot manage to define a test where the user posting data to create an object can registered in the model of the object he just created.

The test

def test_foo_create_form_valid(client, one_user):
    """
    Test the page that lets a user create a Foo object 
    """
    client.force_login(one_user)
    form_input = dict(
        name="foobar",
        description="lorem ipsum dolor",
    )
    url = reverse("foo:add")
    resp = client.post(url, form_input)

    assert resp.status_code == 302  # success

    foo = Foo.objects.last()
    assert foo.description == form_input.get("description")  # success
    assert foo.name == form_input.get("name")  # success
    assert foo.creator == one_user  # this test fail!

The issue

When I run the tests the last one that check the correct association of the logged user and the model he just created is failing with this report : assert None == <User: mcdowelljennifer>. Do you have any idea on what I’m missing ? I feel that I miss something in the client.force_login() but I cannot spot what exactly in the doc…

Related code

See how `one_user` is define

This one_user is a fixture that is define like this:

class UserFactory(DjangoModelFactory):

    username = Faker("user_name")
    email = Faker("email")
    name = Faker("name")

    @post_generation
    def password(
        self, create: bool, extracted: Sequence[Any], **kwargs
    ):
        password = (
            extracted
            if extracted
            else Faker(
                "password",
                length=42,
                special_chars=True,
                digits=True,
                upper_case=True,
                lower_case=True,
            ).generate(extra_kwargs={})
        )
        self.set_password(password)

    class Meta:
        model = get_user_model()
        django_get_or_create = ["username"]

@pytest.fixture
def one_user():
    return UserFactory()
See how the `Foo` model is define
class Cheese(TimeStampedModel):
    name = models.CharField("Name of the cheeese", max_length=255)
    slug = AutoSlugField("foo uri", unique=True, always_update=False, populate_from="name")
    description = models.TextField("Description", blank=True)
    creator = models.ForeignKey(to=settings.AUTH_USER_MODEL, null=True, on_delete=models.SET_NULL)

I don’t see where you’re ever assigning the user to the creator attribute of Cheese. You’re not supplying it in the form_input, nor are you taking any action to assign it to the object being created.

What does the view you’re testing look like?

Sorry it was just an error when writing the code illustration with a more generic foo object. I just corrected it.

The view is implemented like this :

class FooCreateView(LoginRequiredMixin, CreateView):
    model = Foo
    fields = [
        "name",
        "description",
    ]


foo_create_view = FooCreateView.as_view()

and the url is setup like this :

app_name = "foo"
urlpatterns = [
    ...
    path(route="add/", view=foo_create_view, name="add"),
]

Ok, so you’re not setting that attribute in the model. That’s why it’s showing null in your test.

Class FooCreateView(LoginRequiredMixin, CreateView):
    ...
    def form_valid(self, form):
        form.instance.creator = self.request.user
        return super().form_valid(form)

This test was just made to evaluate this part of my view and I didn’t even add it before writing the test… Really sorry !