Files
WiseGrade/backend/tests/test_batch_selection.py
aerospaceboy ebe33392ca fix: improve import, evidence indexing and material-scoped grading
Preserve document revisions and evidence, harden indexing and export behavior, add explicit material selection and direct-folder import, validate model JSON schemas with safe error messages, and retain student selection while loading scoring data.
2026-10-14 13:52:56 +08:00

73 lines
3.4 KiB
Python

"""Explicit batch membership regressions, isolated from real grading and credentials."""
import pytest
from fastapi import HTTPException
from pydantic import ValidationError
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from wisegrade import api, services
from wisegrade.db import Base
from wisegrade.models import CourseVersion, Project, ScoringBatch, Student
from wisegrade.seed import seed_initial
@pytest.fixture
def batch_db(environment):
engine = create_engine("sqlite://")
Base.metadata.create_all(engine)
with Session(engine, expire_on_commit=False) as db:
seed_initial(db)
students = [Student(student_no=f"900000000{i}", name=f"测试{i}") for i in (1, 2, 3)]
db.add_all(students)
db.flush()
other = CourseVersion(course_id=1, version=2, title="另一课程版本", published=True,
objectives=[], indicators=[], directions=[], prompts={}, templates=[])
db.add(other)
db.flush()
db.add_all([Project(student_id=students[0].id, course_version_id=1, topic="项目甲", source_dir="a"),
Project(student_id=students[1].id, course_version_id=1, topic="项目乙", source_dir="b"),
Project(student_id=students[2].id, course_version_id=other.id, topic="其他版本", source_dir="c")])
db.commit()
yield db
engine.dispose()
def test_select_one_project_and_preserve_batch_membership(batch_db):
data = api.BatchInput(course_version_id=1, rubric_version_id=1, project_ids=[2])
created = api.create_batch(data, batch_db)
batch = batch_db.get(ScoringBatch, created["id"])
assert batch.project_ids == [2]
# Importing another project later cannot change this batch's selected membership.
batch_db.add(Project(student_id=1, course_version_id=1, topic="后来导入", source_dir="later"))
batch_db.commit()
assert api.batch_progress(batch.id, batch_db)["project_ids"] == [2]
def test_omitted_selection_preserves_existing_all_projects_api(batch_db):
created = api.create_batch(api.BatchInput(course_version_id=1, rubric_version_id=1), batch_db)
assert batch_db.get(ScoringBatch, created["id"]).project_ids == [1, 2]
@pytest.mark.parametrize("ids", [[999], [3], [2, 2]])
def test_reject_unknown_cross_version_and_duplicate_project_ids(batch_db, ids):
with pytest.raises(HTTPException) as exc:
api.create_batch(api.BatchInput(course_version_id=1, rubric_version_id=1, project_ids=ids), batch_db)
assert exc.value.status_code == 400
assert batch_db.query(ScoringBatch).count() == 0
def test_empty_explicit_selection_cannot_silently_grade_everyone():
with pytest.raises(ValidationError):
api.BatchInput(course_version_id=1, rubric_version_id=1, project_ids=[])
def test_batch_list_uses_saved_human_readable_version_metadata(batch_db):
created = api.create_batch(api.BatchInput(course_version_id=1, rubric_version_id=1, project_ids=[1]), batch_db)
batch = batch_db.get(ScoringBatch, created["id"])
batch.course_snapshot = {**batch.course_snapshot, "version": 7, "title": "创建时课程"}
batch.rubric_snapshot = {**batch.rubric_snapshot, "version": 9}
batch_db.commit()
listed = api.list_batches(batch_db)[0]
assert listed["course_version"] == 7 and listed["course_title"] == "创建时课程"
assert listed["rubric_version"] == 9 and listed["criterion_count"] == 22