Skip to content

tests: replace function-scoped helper fixtures with TestHelper#6709

Open
snejus wants to merge 6 commits into
masterfrom
migrate-helper-test-classes
Open

tests: replace function-scoped helper fixtures with TestHelper#6709
snejus wants to merge 6 commits into
masterfrom
migrate-helper-test-classes

Conversation

@snejus
Copy link
Copy Markdown
Member

@snejus snejus commented Jun 4, 2026

  • Test setup was consolidated into shared helper classes instead of using local helper fixtures.
  • test/library/test_migrations.py now uses MigrationTestHelper to provide one common migration harness, with each test class defining only the legacy state and migration it needs.
  • Plugin tests in test/plugins/test_fuzzy.py, test/plugins/test_missing.py, and test/plugins/utils/test_playcount.py now rely on shared helpers like PluginTestHelper and TestHelper for common setup.

Note: I kept these fixtures in these files

  • test_query.py
  • plugins/test_random.py
  • plugins/test_aura.py
  • plugins/test_lyrics.py

because they intentionally use a higher scope, for example in test_query.py:

@pytest.fixture(scope="class")
def helper():
    helper = TestHelper()
    helper.setup_beets()

    yield helper

    helper.teardown_beets()

Using this setup pattern in test_query.py significantly improved testing durations.

Architecture impact

  • Test infrastructure now follows a clearer base-class pattern for shared setup.
  • Migration tests cleanly separate 'prepare old state' from 'run migration and verify result'.
  • Plugin tests now use the same setup path, which makes new tests easier to add and keeps test structure more consistent across files.

High-level outcome

  • Less duplicated fixture boilerplate.
  • More consistent and easier-to-read test architecture.
  • Tests stay focused on behavior being verified, which should make maintenance and future extension simpler.

Copilot AI review requested due to automatic review settings June 4, 2026 22:26
@snejus snejus requested a review from a team as a code owner June 4, 2026 22:26
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 4, 2026

Thank you for the PR! The changelog has not been updated, so here is a friendly reminder to check if you need to add an entry.

@codecov
Copy link
Copy Markdown

codecov Bot commented Jun 4, 2026

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
2515 1 2514 134
View the top 1 failed test(s) by shortest run time
test\plugins\test_aura.py::plugins::test_aura::TestAuraResponse::test_albums
Stack Traces | 0.006s run time
#x1B[0m#x1B[37m@pytest#x1B[39;49;00m.fixture(scope=#x1B[33m"#x1B[39;49;00m#x1B[33mmodule#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m)#x1B[90m#x1B[39;49;00m
    #x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92mhelper#x1B[39;49;00m():#x1B[90m#x1B[39;49;00m
        helper = TestHelper()#x1B[90m#x1B[39;49;00m
        helper.setup_beets()#x1B[90m#x1B[39;49;00m
    #x1B[90m#x1B[39;49;00m
        #x1B[94myield#x1B[39;49;00m helper#x1B[90m#x1B[39;49;00m
    #x1B[90m#x1B[39;49;00m
>       helper.teardown_beets()#x1B[90m#x1B[39;49;00m

#x1B[1m#x1B[31mtest\plugins\test_aura.py#x1B[0m:23: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
#x1B[1m#x1B[31mbeets\test\helper.py#x1B[0m:240: in teardown_beets
    #x1B[0m#x1B[96mself#x1B[39;49;00m.remove_temp_dir()#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[31mbeets\test\helper.py#x1B[0m:385: in remove_temp_dir
    #x1B[0mshutil.rmtree(#x1B[96mself#x1B[39;49;00m.temp_dir_path)#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[31mC:\hostedtoolcache\windows\Python\3.11.9\x64\Lib\shutil.py#x1B[0m:787: in rmtree
    #x1B[0m#x1B[94mreturn#x1B[39;49;00m _rmtree_unsafe(path, onerror)#x1B[90m#x1B[39;49;00m
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[31mC:\hostedtoolcache\windows\Python\3.11.9\x64\Lib\shutil.py#x1B[0m:634: in _rmtree_unsafe
    #x1B[0monerror(os.unlink, fullname, sys.exc_info())#x1B[90m#x1B[39;49;00m
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

path = WindowsPath('C:/Users/RUNNER~.../Local/Temp/tmpngohsk1g')
onerror = <function rmtree.<locals>.onerror at 0x000001CABF9251C0>

    #x1B[0m#x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92m_rmtree_unsafe#x1B[39;49;00m(path, onerror):#x1B[90m#x1B[39;49;00m
        #x1B[94mtry#x1B[39;49;00m:#x1B[90m#x1B[39;49;00m
            #x1B[94mwith#x1B[39;49;00m os.scandir(path) #x1B[94mas#x1B[39;49;00m scandir_it:#x1B[90m#x1B[39;49;00m
                entries = #x1B[96mlist#x1B[39;49;00m(scandir_it)#x1B[90m#x1B[39;49;00m
        #x1B[94mexcept#x1B[39;49;00m #x1B[96mOSError#x1B[39;49;00m:#x1B[90m#x1B[39;49;00m
            onerror(os.scandir, path, sys.exc_info())#x1B[90m#x1B[39;49;00m
            entries = []#x1B[90m#x1B[39;49;00m
        #x1B[94mfor#x1B[39;49;00m entry #x1B[95min#x1B[39;49;00m entries:#x1B[90m#x1B[39;49;00m
            fullname = entry.path#x1B[90m#x1B[39;49;00m
            #x1B[94mif#x1B[39;49;00m _rmtree_isdir(entry):#x1B[90m#x1B[39;49;00m
                #x1B[94mtry#x1B[39;49;00m:#x1B[90m#x1B[39;49;00m
                    #x1B[94mif#x1B[39;49;00m entry.is_symlink():#x1B[90m#x1B[39;49;00m
                        #x1B[90m# This can only happen if someone replaces#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
                        #x1B[90m# a directory with a symlink after the call to#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
                        #x1B[90m# os.scandir or entry.is_dir above.#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
                        #x1B[94mraise#x1B[39;49;00m #x1B[96mOSError#x1B[39;49;00m(#x1B[33m"#x1B[39;49;00m#x1B[33mCannot call rmtree on a symbolic link#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m)#x1B[90m#x1B[39;49;00m
                #x1B[94mexcept#x1B[39;49;00m #x1B[96mOSError#x1B[39;49;00m:#x1B[90m#x1B[39;49;00m
                    onerror(os.path.islink, fullname, sys.exc_info())#x1B[90m#x1B[39;49;00m
                    #x1B[94mcontinue#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
                _rmtree_unsafe(fullname, onerror)#x1B[90m#x1B[39;49;00m
            #x1B[94melse#x1B[39;49;00m:#x1B[90m#x1B[39;49;00m
                #x1B[94mtry#x1B[39;49;00m:#x1B[90m#x1B[39;49;00m
>                   os.unlink(fullname)#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[31mE                   PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: 'C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\tmpngohsk1g\\library.db'#x1B[0m

#x1B[1m#x1B[31mC:\hostedtoolcache\windows\Python\3.11.9\x64\Lib\shutil.py#x1B[0m:632: PermissionError

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

grug see PR make test setup less copy-paste. instead of local helper fixtures per file, tests now inherit shared helper classes (TestHelper/PluginTestHelper) and migration tests get one common harness.

Changes:

  • swap function-scoped helper fixtures for TestHelper / PluginTestHelper base classes in plugin tests
  • add MigrationTestHelper harness so each migration test only defines legacy setup + migration under test
  • adjust playcount tests to use class-based helper + explicit log fixture injection

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
test/plugins/utils/test_playcount.py move from helper fixture to TestHelper inheritance; pass logger via fixture
test/plugins/test_missing.py use shared PluginTestHelper (plus IO mixin) for missing plugin CLI tests
test/plugins/test_fuzzy.py use PluginTestHelper for fuzzy plugin tests; remove local helper fixture
test/library/test_migrations.py introduce MigrationTestHelper and refactor migrations tests onto shared harness

Comment thread test/library/test_migrations.py
snejus added 6 commits June 6, 2026 10:54
- Replace local setup fixtures with existing test helper base classes to reduce
  duplicated test setup.
- Centralize migration test setup in a shared helper and update the migration
  tests to use the common pre-migration initialization flow.
- This removes repeated fixture boilerplate while keeping each test focused on
  the migration behavior it verifies.
- Replace duplicate pytest import helper fixtures with PluginMixin-based setup
  helpers.
- Keep plugin import tests aligned with shared beets setup behavior.
- Dropped unused MusicBrainZ and Subsonic test helpers and imports.
- Keeps plugin test modules focused on the behavior they still exercise.
@snejus snejus force-pushed the migrate-helper-test-classes branch from 7de9e4d to f38bad8 Compare June 6, 2026 09:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants