pytest-dev / pytest-factoryboy

factory_boy integration the pytest runner
MIT License
356 stars 41 forks source link

Using `factory.List` resolves in unusable fixtures #67

Open sobolevn opened 5 years ago

sobolevn commented 5 years ago

Setup

Here are my models:

from typing import List

from mypy_extensions import TypedDict

class WakatimeCommit(TypedDict):
    """Class to represent a single Wakatime commit instance from API. """

    hash: str
    author_email: str

class WakatimeCommitsResponse(TypedDict):
    """Class to represent Wakatime response from commits API."""

    commits: List[WakatimeCommit]

And my factories:

import factory
from pytest_factoryboy import register

@register
class WakatimeCommitFactory(factory.BaseDictFactory):
    """
    Fake factory for a single Wakatime commit entry.

    Note:
        This class is marked as protected and is not registered,
        since we do not actually need a single commit in tests.

    """

    class Meta(object):
        model = WakatimeCommit

    hash = '123abc'
    author_email = 'some@email.com'

@register
class WakatimeCommitsResponseFactory(factory.BaseDictFactory):
    """Fake factory for Wakatime `/commits` response."""

    class Meta(object):
        model = WakatimeCommitsResponse

    commits = factory.List([
        factory.SubFactory(WakatimeCommitFactory) for _ in range(10)
    ])

And finally my test:

def test_pipeline_for_opened_valid_mr(
    wakatime_commits_response,
):
    """
    Tests the whole process of adding spent time to a merge request.

    All requests are mocked, everything returns valid responses.
    """
    print(wakatime_commits_response)

    assert 1 == 2

Error

This tests fails due to unresolved fixtures:

def test_pipeline_for_opened_valid_mr(
file <string>, line 2: source code not available
file <string>, line 2: source code not available
E       fixture 'list' not found
>       available fixtures:
...
wakatime_commit, wakatime_commit__author_email, wakatime_commit__hash, wakatime_commit__total_seconds, wakatime_commit_factory, wakatime_commits_response, wakatime_commits_response__commits, wakatime_commits_response_factory
...

I guess this happens due to the fact that I am using factory.List.

Workaround

class WakatimeCommitsResponseFactory(factory.BaseDictFactory):
    ...

    @factory.post_generation
    def commits(self, create, extracted, **kwargs):
        if extracted:
            self['commits'] = extracted
        else:
            self['commits'] = []
            for _ in range(10):
                self['commits'].append(WakatimeCommitFactory.build())
skarzi commented 5 years ago

I can take this issue as well as https://github.com/pytest-dev/pytest-factoryboy/issues/65, because it affected me several times. Could someone give me some directions firstly? I am still looking for the clearest solution for that

sobolevn commented 5 years ago

Awesome, @skarzi! I would appreciate a fix. Sadly, I am not familiar with the codebase.

skarzi commented 3 years ago

Currently it's really hard to implement factory.declarations.List and factory.declarations.Dict support in a proper way, because of few reasons:

from dataclasses import dataclass 

import factory
from pytest_factoryboy import LazyFixture, register

@dataclass
class Author:
    full_name: str

@dataclass
class Book:
    author: Author
    title: str

class AuthorFactory(factory.Factory):
    full_name = factory.Sequence(lambda counter: f'Author {counter}')

    class Meta:
        model = Author

class LemonySnicketBookFactory(factory.Factory):
    author = factory.SubFactory(AuthorFactory, full_name='Lemony Snicket')
    title = factory.Sequence(lambda counter: f'A Series of Unfortunate Events {counter}')

    class Meta:
        model = Book

register(AuthorFactory)
register(LemonySnicketBookFactory, _name='lemony_snicket_book')

def test_subfactory_defaults(lemony_snicket_book):
    """Failure because ``lemony_snicket_book.author.full_name`` is ``'Author 1'``"""
    assert lemony_snicket_book.author.full_name == 'Lemony Snicket'

So with my current knowledge, I see 2 possible solutions:

I am still not so much into pytest-factoryboy and factoryboy codebase, because it's really dynamic and sometimes hard to debug code, so any responses with feedback or any advice is really welcome!

skarzi commented 3 years ago

@youtux @hugovk maybe do you have any ideas/insights about this issue and the comment I have added above?

lovetoburnswhen commented 2 years ago

@skarzi did you ever get around to a fix?

skarzi commented 2 years ago

Unfortunately not fully :(

It would be great to discuss this issue with some more experienced pytest-factoryboy developers

ryancausey commented 4 months ago

I just ran into this issue. Is there any idea on how to solve this?