joseph-roitman / pytest-snapshot

A plugin for snapshot testing with pytest.
MIT License
114 stars 12 forks source link

Dealing with callable #68

Open e-belair opened 7 months ago

e-belair commented 7 months ago

I have a test that checks some config objects that contains refs to callable functions like this:

@dataclass
class ExportConfig:

    sql_query: str

    output_file: Path

    format_fields: dict[
        str,
        Callable[[Any], Any],
    ] | None = None

When I test with update-snapshot, the generated snapshot contains a ref to the callable function that changes every time I start the tests.

    def test_export_config(self, tmp_path, snapshot):
        config = ExportConfig(
            'select * from table',
            Path(tmp_path, 'test_export_config.csv'),
            {
                'some_field': format_tel # ref to the function
            }
        )
        assert config == snapshot

So when I execute tests with --snapshot-update, the generated ambr file look like this:

# name: TestSqlExporter.test_export_config
  ExportConfig(sql_query='select * from table', output_file=PosixPath('test_export_config.csv'), format_fields={'format_tel': <function format_tel at 0x7f450411db20>})

But when I execute the test without --snapshot-update, I get the following error:

self = <tests.helpers.test_sql_exporter.TestSqlExporter object at 0x7f29e104c250>
snapshot = ExportConfig(sql_query='select * from table', output_file=PosixPath('test_export_config.csv'), format_fields={'format_tel': <function format_tel at 0x7f450411db20>})

    def test_export_config(self, snapshot):
        config = ExportConfig(
            'select * from table',
            Path('test_export_config.csv'),
            {
                'format_tel': format_tel
            }
        )
>       assert config == snapshot
E       AssertionError: assert [+ received] == [- snapshot]
E         - ExportConfig(sql_query='select * from table', output_file=PosixPath('test_export_config.csv'), format_fields={'format_tel': <function format_tel at 0x7f450411db20>})
E         + ExportConfig(sql_query='select * from table', output_file=PosixPath('test_export_config.csv'), format_fields={'format_tel': <function format_tel at 0x7f2a18921c60>})

How can I deal with this case?

e-belair commented 7 months ago

I found a way to solve the problem by using a function to remove object addresses like this:

_object_address_regex = re.compile(r'0x[a-z0-9]{12}')
def _repr_without_object_addresses(obj: Any) -> str:
    return re.sub(_object_address_regex, '', obj.__repr__())

And then use like this in my test:

assert _repr_without_object_addresses(config) == snapshot

But I'm not sure it's the best way to do :thinking: