Skip to content

Commit 8471bd9

Browse files
committed
test(orm): refactor DBSeedCommand tests to class-based app-driven style
Port the class-based unittest.TestCase refactor onto this branch: setUp builds the app via fixtures.app.create_app(), happy-path coverage runs through the registered console app against real fixture seeders, and the option/argument-resolution tests assert the Seeder call directly (autospec mock) instead of relying on console output. Exception paths keep asserting via CommandTester. Adapted to this branch's pre-rename masoniteorm.seeds module path since it has not yet picked up the seeds -> seeders rename.
1 parent 76551b2 commit 8471bd9

7 files changed

Lines changed: 130 additions & 53 deletions

File tree

fastapi_startkit/tests/masoniteorm/commands/fixtures/databases/seeds/__init__.py

Whitespace-only changes.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from fastapi_startkit.masoniteorm.seeds import Seeder
2+
3+
from .recorder import CALLS
4+
5+
6+
class DatabaseSeeder(Seeder):
7+
async def run(self):
8+
CALLS.append(("database", self.connection))
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
"""Shared call recorder used by the fixture seeder classes below."""
2+
3+
CALLS = []
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from fastapi_startkit.masoniteorm.seeds import Seeder
2+
3+
from .recorder import CALLS
4+
5+
6+
class SampleSeeder(Seeder):
7+
async def run(self):
8+
CALLS.append(("sample", self.connection))
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from fastapi_startkit.masoniteorm.seeds import Seeder
2+
3+
from .recorder import CALLS
4+
5+
6+
class SpecialSeeder(Seeder):
7+
async def run(self):
8+
CALLS.append(("special", self.connection))
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from fastapi_startkit.masoniteorm.seeds import Seeder
2+
3+
from .recorder import CALLS
4+
5+
6+
class UserTableSeeder(Seeder):
7+
async def run(self):
8+
CALLS.append(("user_table", self.connection))

fastapi_startkit/tests/masoniteorm/commands/test_db_seed_command.py

Lines changed: 95 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,96 +1,138 @@
1+
import io
12
import unittest
3+
from contextlib import redirect_stdout
24
from unittest import mock
35

46
from cleo.testers.command_tester import CommandTester
57

68
from fastapi_startkit.masoniteorm.commands.DBSeedCommand import DBSeedCommand
79

10+
from .fixtures.databases.seeds.recorder import CALLS
811

9-
class FakeSeeder:
10-
"""Records constructor args and awaited methods, mocking DB side effects."""
11-
12-
instances = []
13-
14-
def __init__(self, seed_path="databases/seeds", connection=None):
15-
self.seed_path = seed_path
16-
self.connection = connection
17-
self.calls = []
18-
FakeSeeder.instances.append(self)
19-
20-
async def run_database_seed(self):
21-
self.calls.append(("run_database_seed", None))
22-
23-
async def run_specific_seed(self, seed):
24-
self.calls.append(("run_specific_seed", seed))
12+
FIXTURE_SEED_PATH = "tests.masoniteorm.commands.fixtures.databases.seeds"
2513

2614

2715
class TestDBSeedCommand(unittest.TestCase):
2816
def setUp(self):
29-
FakeSeeder.instances = []
30-
patcher = mock.patch(
31-
"fastapi_startkit.masoniteorm.seeds.Seeder",
32-
FakeSeeder,
33-
)
34-
patcher.start()
35-
self.addCleanup(patcher.stop)
17+
from .fixtures.app import create_app
18+
19+
self.app = create_app()
20+
CALLS.clear()
21+
22+
def tearDown(self):
23+
CALLS.clear()
3624

3725
def _run(self, args=""):
3826
tester = CommandTester(DBSeedCommand())
3927
tester.execute(args)
4028
return tester.io.fetch_output()
4129

30+
def _run_app(self, args=""):
31+
buffer = io.StringIO()
32+
with redirect_stdout(buffer):
33+
self.app.run("db:seed", args)
34+
return buffer.getvalue()
35+
36+
# -- option/argument resolution, exercised against a mocked Seeder --
37+
4238
def test_runs_database_seeder_by_default(self):
43-
output = self._run("")
39+
with mock.patch("fastapi_startkit.masoniteorm.seeds.Seeder", autospec=True) as MockSeeder:
40+
output = self._run("")
4441

4542
self.assertIn("Database Seeder seeded!", output)
46-
seeder = FakeSeeder.instances[-1]
47-
self.assertEqual(seeder.calls, [("run_database_seed", None)])
48-
self.assertEqual(seeder.seed_path, "databases/seeds")
49-
self.assertEqual(seeder.connection, "default")
43+
MockSeeder.assert_called_once_with(seed_path="databases/seeds", connection="default")
44+
MockSeeder.return_value.run_database_seed.assert_awaited_once_with()
45+
MockSeeder.return_value.run_specific_seed.assert_not_awaited()
5046

5147
def test_seeds_specific_table_from_argument(self):
52-
output = self._run("posts")
48+
with mock.patch("fastapi_startkit.masoniteorm.seeds.Seeder", autospec=True) as MockSeeder:
49+
output = self._run("posts")
5350

5451
self.assertIn("PostsTableSeeder seeded!", output)
55-
seeder = FakeSeeder.instances[-1]
56-
self.assertEqual(
57-
seeder.calls,
58-
[("run_specific_seed", "posts_table_seeder.PostsTableSeeder")],
59-
)
52+
MockSeeder.return_value.run_specific_seed.assert_awaited_once_with("posts_table_seeder.PostsTableSeeder")
6053

6154
def test_class_option_resolves_plain_class_name(self):
62-
output = self._run("--class PostSeeder")
55+
with mock.patch("fastapi_startkit.masoniteorm.seeds.Seeder", autospec=True) as MockSeeder:
56+
output = self._run("--class PostSeeder")
6357

6458
self.assertIn("PostSeeder seeded!", output)
65-
seeder = FakeSeeder.instances[-1]
66-
self.assertEqual(
67-
seeder.calls,
68-
[("run_specific_seed", "post_seeder.PostSeeder")],
69-
)
59+
MockSeeder.return_value.run_specific_seed.assert_awaited_once_with("post_seeder.PostSeeder")
7060

7161
def test_class_option_resolves_table_seeder_suffix(self):
72-
output = self._run("--class PostTableSeeder")
62+
with mock.patch("fastapi_startkit.masoniteorm.seeds.Seeder", autospec=True) as MockSeeder:
63+
output = self._run("--class PostTableSeeder")
7364

7465
self.assertIn("PostTableSeeder seeded!", output)
75-
seeder = FakeSeeder.instances[-1]
76-
self.assertEqual(
77-
seeder.calls,
78-
[("run_specific_seed", "post_table_seeder.PostTableSeeder")],
79-
)
66+
MockSeeder.return_value.run_specific_seed.assert_awaited_once_with("post_table_seeder.PostTableSeeder")
8067

8168
def test_class_option_accepts_dotted_path(self):
82-
output = self._run("--class custom.MySeeder")
69+
with mock.patch("fastapi_startkit.masoniteorm.seeds.Seeder", autospec=True) as MockSeeder:
70+
output = self._run("--class custom.MySeeder")
8371

8472
self.assertIn("MySeeder seeded!", output)
85-
seeder = FakeSeeder.instances[-1]
86-
self.assertEqual(seeder.calls, [("run_specific_seed", "custom.MySeeder")])
73+
MockSeeder.return_value.run_specific_seed.assert_awaited_once_with("custom.MySeeder")
8774

8875
def test_connection_and_directory_options_are_forwarded(self):
89-
self._run("--connection sqlite --directory db/seeds")
76+
with mock.patch("fastapi_startkit.masoniteorm.seeds.Seeder", autospec=True) as MockSeeder:
77+
self._run("--connection sqlite --directory db/seeds")
78+
79+
MockSeeder.assert_called_once_with(seed_path="db/seeds", connection="sqlite")
80+
81+
# -- end-to-end, driven through the registered console app against real fixture seeders --
82+
83+
def test_runs_database_seeder_by_default_via_app(self):
84+
output = self._run_app(f"--directory {FIXTURE_SEED_PATH} --connection sqlite")
85+
86+
self.assertIn("Database Seeder seeded!", output)
87+
self.assertEqual(CALLS, [("database", "sqlite")])
88+
89+
def test_runs_seeder_for_table_argument_via_app(self):
90+
output = self._run_app(f"user --directory {FIXTURE_SEED_PATH} --connection sqlite")
91+
92+
self.assertIn("UserTableSeeder seeded!", output)
93+
self.assertEqual(CALLS, [("user_table", "sqlite")])
94+
95+
def test_runs_seeder_for_class_option_without_table_suffix_via_app(self):
96+
output = self._run_app(f"--directory {FIXTURE_SEED_PATH} --class SampleSeeder --connection sqlite")
97+
98+
self.assertIn("SampleSeeder seeded!", output)
99+
self.assertEqual(CALLS, [("sample", "sqlite")])
100+
101+
def test_runs_seeder_for_class_option_with_table_suffix_via_app(self):
102+
output = self._run_app(f"--directory {FIXTURE_SEED_PATH} --class UserTableSeeder --connection sqlite")
103+
104+
self.assertIn("UserTableSeeder seeded!", output)
105+
self.assertEqual(CALLS, [("user_table", "sqlite")])
106+
107+
def test_runs_seeder_for_fully_qualified_class_option_via_app(self):
108+
output = self._run_app(
109+
f"--directory {FIXTURE_SEED_PATH} --class special_seeder.SpecialSeeder --connection sqlite"
110+
)
111+
112+
self.assertIn("SpecialSeeder seeded!", output)
113+
self.assertEqual(CALLS, [("special", "sqlite")])
114+
115+
def test_class_option_takes_precedence_over_table_argument_via_app(self):
116+
output = self._run_app(f"user --directory {FIXTURE_SEED_PATH} --class SampleSeeder --connection sqlite")
117+
118+
self.assertIn("SampleSeeder seeded!", output)
119+
self.assertEqual(CALLS, [("sample", "sqlite")])
120+
121+
def test_uses_default_connection_option_via_app(self):
122+
self._run_app(f"--directory {FIXTURE_SEED_PATH}")
123+
124+
self.assertEqual(CALLS, [("database", "default")])
125+
126+
# -- error paths: driven directly through CommandTester, since the console
127+
# application catches command exceptions instead of propagating them --
128+
129+
def test_raises_when_seeder_class_cannot_be_found(self):
130+
with self.assertRaises(ValueError):
131+
self._run(f"--directory {FIXTURE_SEED_PATH} --class does_not_exist.NopeSeeder --connection sqlite")
90132

91-
seeder = FakeSeeder.instances[-1]
92-
self.assertEqual(seeder.seed_path, "db/seeds")
93-
self.assertEqual(seeder.connection, "sqlite")
133+
def test_raises_when_database_seeder_missing_from_directory(self):
134+
with self.assertRaises(ValueError):
135+
self._run("--directory tests.masoniteorm.commands.fixtures.databases.migrations --connection sqlite")
94136

95137

96138
if __name__ == "__main__":

0 commit comments

Comments
 (0)