G Plotur
G Plotur

Reputation: 71

Rewrite model @property in Factory Boy's object factory

I want to find a way to properly test my code with Factory Boy.

There are a model, like this:

from django.db import models

class MyModel(models.Model):
    param1 = <some field>
    param1 = <some field>
    param1 = <some field>

    @property
    def is_smth(self):
        <some complicated code that returns boolean>

There is a factory for this model:

import factory

class MyModelFactory(factory.DjangoModelFactory):
    param1 = <some value>
    param2 = <some value>
    param3 = <some value>

    # And here i need to "rewrite" property of the model
    # so that it would always return true

Can anyone help me with that? I didn't found mentions about this in factory boy's documentation, and various variants i've tried doesn't seem to work.

Upvotes: 7

Views: 2545

Answers (3)

Ranel Padon
Ranel Padon

Reputation: 605

The suggestion of @StasEvseev didn't work in our case. I ended up leveraging the Factory Boy's post_generation hooks since our property is calculating the value based on other models/data. Hence, building the data needed by @is_smth will make it to behave/evaluate as intended when that property is called:

class MyModelFactory(factory.DjangoModelFactory):
    ...

    @factory.post_generation
    def prepare_data_for_is_smth(self, create, extracted, **kwargs):
       # Populate/build here the models/fields needed for your
       # <some complicated code that returns boolean>.

Post generation hooks are executed after creating the factory instance. You could further customize the hook's behavior by utilizing the extracted and kwargs parameters, which are passed in the factory class using the ATTR__SUBATTR format (e.g. MyModelFactory(foo__bar=SOME_VALUE).

Upvotes: 2

StasEvseev
StasEvseev

Reputation: 105

As Suganthi said, you can using mock.

But I offer another solution:

 @classmethod
 def _create(cls, model_class, *args, **kwargs):   
     with mock.patch('MyModel.is_smth',
                     new_callable=mock.PropertyMock) as m:
         m.return_value = True
         return super()._create(model_class, *args, **kwargs)

Just mock property during generation models. It works on factoryboy==2.5.2

Upvotes: 5

Suganthi
Suganthi

Reputation: 417

Have you tried using mocks?

def test_is_smith(self):
    mymodel = MyModel()
    with mock.patch('MyModel.is_smith', new_callable=mock.PropertyMock) as mocked_model:
        mocked_model.return_value = True
        self.assertTrue(mymodel.is_smith)

Upvotes: 2

Related Questions