Skip to content

Commit dd85518

Browse files
Copilotchefgs
andcommitted
Add CLI integration tests for scaffold unittest command
Co-authored-by: chefgs <7605658+chefgs@users.noreply.github.com>
1 parent c212f67 commit dd85518

1 file changed

Lines changed: 212 additions & 3 deletions

File tree

cli/test_cli.py

Lines changed: 212 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ def test_scaffold_help_lists_new_targets():
194194
assert "gitlab" in result.stdout
195195
assert "argocd" in result.stdout
196196
assert "sre" in result.stdout
197+
assert "unittest" in result.stdout
197198

198199
def test_scaffold_gha_via_cli():
199200
"""Regression: `python -m cli.devopsos scaffold gha` must not raise argparse error."""
@@ -596,11 +597,11 @@ def test_process_first_specific_section_no_usage_footer():
596597
# -- scaffold arg pass-through (cli.devopsos vs cli.scaffold_*) ------------
597598

598599
def test_scaffold_help_shows_all_subcommands():
599-
"""`devopsos scaffold --help` lists all 7 scaffold subcommands."""
600+
"""`devopsos scaffold --help` lists all 8 scaffold subcommands."""
600601
result = _run(["-m", "cli.devopsos", "scaffold", "--help"])
601602
assert result.returncode == 0
602603
text = _strip_ansi(result.stdout)
603-
for target in ("gha", "jenkins", "gitlab", "argocd", "sre", "devcontainer", "cicd"):
604+
for target in ("gha", "jenkins", "gitlab", "argocd", "sre", "devcontainer", "cicd", "unittest"):
604605
assert target in text, f"scaffold --help should list the '{target}' subcommand"
605606

606607

@@ -759,11 +760,219 @@ def test_scaffold_cicd_jenkins_only():
759760
)
760761

761762

763+
# ── scaffold unittest (new in v0.4.0) ────────────────────────────────────────
764+
765+
def test_scaffold_unittest_help_shows_native_options():
766+
"""`devopsos scaffold unittest --help` shows all unittest-specific options."""
767+
result = _run(["-m", "cli.devopsos", "scaffold", "unittest", "--help"])
768+
assert result.returncode == 0
769+
text = _strip_ansi(result.stdout)
770+
for option in ("--name", "--languages", "--framework", "--coverage", "--output-dir"):
771+
assert option in text, f"scaffold unittest --help should show '{option}'"
772+
# Supported languages / frameworks must be mentioned in the help text
773+
assert "python" in text.lower()
774+
assert "javascript" in text.lower()
775+
assert "typescript" in text.lower()
776+
assert "go" in text.lower()
777+
assert "jest" in text.lower()
778+
779+
780+
def test_scaffold_unittest_via_cli_python():
781+
"""`devopsos scaffold unittest --languages python` generates pytest.ini and conftest.py."""
782+
with tempfile.TemporaryDirectory() as tmp:
783+
result = subprocess.run(
784+
[
785+
sys.executable, "-m", "cli.devopsos",
786+
"scaffold", "unittest",
787+
"--name", "my-api",
788+
"--languages", "python",
789+
"--output-dir", tmp,
790+
],
791+
capture_output=True, text=True,
792+
cwd=os.path.dirname(os.path.dirname(__file__)),
793+
)
794+
assert result.returncode == 0, result.stderr + result.stdout
795+
assert "error: unrecognized arguments" not in result.stderr
796+
assert (Path(tmp) / "pytest.ini").is_file(), "pytest.ini should be created"
797+
assert (Path(tmp) / "conftest.py").is_file(), "conftest.py should be created"
798+
assert (Path(tmp) / "tests" / "test_sample.py").is_file(), "test_sample.py should be created"
799+
assert (Path(tmp) / "tests" / "__init__.py").is_file(), "tests/__init__.py should be created"
800+
# pytest.ini must reference the project name
801+
ini_content = (Path(tmp) / "pytest.ini").read_text()
802+
assert "testpaths" in ini_content
803+
assert "--cov=" in ini_content # coverage enabled by default
804+
805+
806+
def test_scaffold_unittest_via_cli_javascript_jest():
807+
"""`devopsos scaffold unittest --languages javascript --framework jest` generates jest.config.js."""
808+
with tempfile.TemporaryDirectory() as tmp:
809+
result = subprocess.run(
810+
[
811+
sys.executable, "-m", "cli.devopsos",
812+
"scaffold", "unittest",
813+
"--name", "my-lib",
814+
"--languages", "javascript",
815+
"--framework", "jest",
816+
"--output-dir", tmp,
817+
],
818+
capture_output=True, text=True,
819+
cwd=os.path.dirname(os.path.dirname(__file__)),
820+
)
821+
assert result.returncode == 0, result.stderr + result.stdout
822+
assert (Path(tmp) / "jest.config.js").is_file(), "jest.config.js should be created"
823+
assert (Path(tmp) / "tests" / "sample.test.js").is_file(), "sample.test.js should be created"
824+
jest_content = (Path(tmp) / "jest.config.js").read_text()
825+
assert "testEnvironment" in jest_content
826+
assert "collectCoverage" in jest_content # coverage enabled by default
827+
828+
829+
def test_scaffold_unittest_via_cli_typescript_vitest():
830+
"""`devopsos scaffold unittest --languages typescript --framework vitest` creates vitest.config.js."""
831+
with tempfile.TemporaryDirectory() as tmp:
832+
result = subprocess.run(
833+
[
834+
sys.executable, "-m", "cli.devopsos",
835+
"scaffold", "unittest",
836+
"--name", "my-ui",
837+
"--languages", "typescript",
838+
"--framework", "vitest",
839+
"--output-dir", tmp,
840+
],
841+
capture_output=True, text=True,
842+
cwd=os.path.dirname(os.path.dirname(__file__)),
843+
)
844+
assert result.returncode == 0, result.stderr + result.stdout
845+
assert (Path(tmp) / "vitest.config.js").is_file(), "vitest.config.js should be created"
846+
assert (Path(tmp) / "tests" / "sample.test.ts").is_file(), "sample.test.ts should be created"
847+
vitest_content = (Path(tmp) / "vitest.config.js").read_text()
848+
assert "defineConfig" in vitest_content
849+
assert "vitest/config" in vitest_content
850+
851+
852+
def test_scaffold_unittest_via_cli_javascript_mocha():
853+
"""`devopsos scaffold unittest --languages javascript --framework mocha` generates .mocharc.js."""
854+
with tempfile.TemporaryDirectory() as tmp:
855+
result = subprocess.run(
856+
[
857+
sys.executable, "-m", "cli.devopsos",
858+
"scaffold", "unittest",
859+
"--name", "my-service",
860+
"--languages", "javascript",
861+
"--framework", "mocha",
862+
"--output-dir", tmp,
863+
],
864+
capture_output=True, text=True,
865+
cwd=os.path.dirname(os.path.dirname(__file__)),
866+
)
867+
assert result.returncode == 0, result.stderr + result.stdout
868+
assert (Path(tmp) / ".mocharc.js").is_file(), ".mocharc.js should be created"
869+
assert (Path(tmp) / "tests" / "sample.test.js").is_file(), "sample.test.js should be created"
870+
mocha_content = (Path(tmp) / ".mocharc.js").read_text()
871+
assert "spec" in mocha_content
872+
assert "tests/**" in mocha_content
873+
874+
875+
def test_scaffold_unittest_via_cli_go():
876+
"""`devopsos scaffold unittest --languages go` generates a Go test file and Makefile."""
877+
with tempfile.TemporaryDirectory() as tmp:
878+
result = subprocess.run(
879+
[
880+
sys.executable, "-m", "cli.devopsos",
881+
"scaffold", "unittest",
882+
"--name", "my-server",
883+
"--languages", "go",
884+
"--output-dir", tmp,
885+
],
886+
capture_output=True, text=True,
887+
cwd=os.path.dirname(os.path.dirname(__file__)),
888+
)
889+
assert result.returncode == 0, result.stderr + result.stdout
890+
assert (Path(tmp) / "my_server_test.go").is_file(), "my_server_test.go should be created"
891+
assert (Path(tmp) / "Makefile.test").is_file(), "Makefile.test should be created"
892+
go_content = (Path(tmp) / "my_server_test.go").read_text()
893+
assert '"testing"' in go_content
894+
assert "TestTableDriven" in go_content
895+
makefile_content = (Path(tmp) / "Makefile.test").read_text()
896+
assert "go test" in makefile_content
897+
assert "test-cov:" in makefile_content
898+
899+
900+
def test_scaffold_unittest_via_cli_multi_language():
901+
"""`devopsos scaffold unittest --languages python,javascript,go` generates files for all three."""
902+
with tempfile.TemporaryDirectory() as tmp:
903+
result = subprocess.run(
904+
[
905+
sys.executable, "-m", "cli.devopsos",
906+
"scaffold", "unittest",
907+
"--name", "full-stack",
908+
"--languages", "python,javascript,go",
909+
"--output-dir", tmp,
910+
],
911+
capture_output=True, text=True,
912+
cwd=os.path.dirname(os.path.dirname(__file__)),
913+
)
914+
assert result.returncode == 0, result.stderr + result.stdout
915+
# Python files
916+
assert (Path(tmp) / "pytest.ini").is_file(), "pytest.ini should be created"
917+
assert (Path(tmp) / "tests" / "test_sample.py").is_file(), "test_sample.py should be created"
918+
# JavaScript files (default: jest)
919+
assert (Path(tmp) / "jest.config.js").is_file(), "jest.config.js should be created"
920+
# Go files
921+
assert (Path(tmp) / "full_stack_test.go").is_file(), "full_stack_test.go should be created"
922+
assert (Path(tmp) / "Makefile.test").is_file(), "Makefile.test should be created"
923+
924+
925+
def test_scaffold_unittest_no_coverage_flag():
926+
"""`--no-coverage` removes coverage configuration from generated files."""
927+
with tempfile.TemporaryDirectory() as tmp:
928+
result = subprocess.run(
929+
[
930+
sys.executable, "-m", "cli.devopsos",
931+
"scaffold", "unittest",
932+
"--name", "lean-app",
933+
"--languages", "python",
934+
"--no-coverage",
935+
"--output-dir", tmp,
936+
],
937+
capture_output=True, text=True,
938+
cwd=os.path.dirname(os.path.dirname(__file__)),
939+
)
940+
assert result.returncode == 0, result.stderr + result.stdout
941+
ini_content = (Path(tmp) / "pytest.ini").read_text()
942+
assert "--cov=" not in ini_content, "pytest.ini should not contain --cov= when --no-coverage is set"
943+
944+
945+
def test_scaffold_unittest_via_cli_matches_direct_module_output():
946+
"""Output from `devopsos scaffold unittest` equals `python -m cli.scaffold_unittest` (same defaults)."""
947+
with tempfile.TemporaryDirectory() as tmp1, tempfile.TemporaryDirectory() as tmp2:
948+
common_args = ["--name", "test-app", "--languages", "python"]
949+
950+
result_unified = subprocess.run(
951+
[sys.executable, "-m", "cli.devopsos", "scaffold", "unittest"]
952+
+ common_args + ["--output-dir", tmp1],
953+
capture_output=True, text=True,
954+
cwd=os.path.dirname(os.path.dirname(__file__)),
955+
)
956+
result_direct = subprocess.run(
957+
[sys.executable, "-m", "cli.scaffold_unittest"]
958+
+ common_args + ["--output-dir", tmp2],
959+
capture_output=True, text=True,
960+
cwd=os.path.dirname(os.path.dirname(__file__)),
961+
)
962+
963+
assert result_unified.returncode == 0, result_unified.stderr
964+
assert result_direct.returncode == 0, result_direct.stderr
965+
# Both must produce identical pytest.ini content
966+
assert (Path(tmp1) / "pytest.ini").read_text() == (Path(tmp2) / "pytest.ini").read_text(), (
967+
"Unified CLI and direct module should produce identical pytest.ini"
968+
)
969+
970+
762971
# ── graceful exit (no opts) ──────────────────────────────────────────────────
763972

764973
def test_scaffold_no_opts_shows_help():
765974
"""Each scaffold subcommand shows usage help (not an error) when invoked with no options."""
766-
targets = ("gha", "jenkins", "gitlab", "argocd", "sre", "devcontainer", "cicd")
975+
targets = ("gha", "jenkins", "gitlab", "argocd", "sre", "devcontainer", "cicd", "unittest")
767976
for target in targets:
768977
result = subprocess.run(
769978
[sys.executable, "-m", "cli.devopsos", "scaffold", target],

0 commit comments

Comments
 (0)