""" 原料管理GUI测试模块 使用PyQt测试框架测试GUI交互和业务逻辑 """ import unittest import os import sys import tempfile from PyQt5.QtWidgets import QApplication, QMessageBox, QTabWidget from PyQt5.QtTest import QTest from PyQt5.QtCore import Qt # 添加父目录到路径以导入模块 sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from database import DatabaseManager from raw_material_dialog import RawMaterialLibraryDialog class TestRawMaterialGUI(unittest.TestCase): """原料管理GUI测试类""" @classmethod def setUpClass(cls): """测试类初始化:创建QApplication实例""" cls.app = QApplication.instance() if cls.app is None: cls.app = QApplication(sys.argv) def setUp(self): """每个测试前准备:创建临时数据库和对话框""" self.temp_dir = tempfile.mkdtemp() self.db_path = os.path.join(self.temp_dir, "test_fabric.db") self.db_manager = DatabaseManager(self.db_path) # 创建对话框实例(管理员模式) self.dialog = RawMaterialLibraryDialog(self.db_path, is_admin=True) # 禁用消息框以便自动化测试 self._original_msgbox = QMessageBox.information self._original_warning = QMessageBox.warning self._original_critical = QMessageBox.critical self._original_question = QMessageBox.question # Mock消息框 QMessageBox.information = lambda *args, **kwargs: None QMessageBox.warning = lambda *args, **kwargs: None QMessageBox.critical = lambda *args, **kwargs: None QMessageBox.question = lambda *args, **kwargs: QMessageBox.Yes def tearDown(self): """每个测试后清理""" # 恢复消息框 QMessageBox.information = self._original_msgbox QMessageBox.warning = self._original_warning QMessageBox.critical = self._original_critical QMessageBox.question = self._original_question # 关闭对话框 self.dialog.close() self.dialog.deleteLater() # 清理数据库 import gc gc.collect() try: if os.path.exists(self.db_path): os.remove(self.db_path) if os.path.exists(self.temp_dir): os.rmdir(self.temp_dir) except: pass # ========== 添加原料GUI测试 ========== def test_add_raw_material_basic_gui(self): """测试通过GUI添加基本原料""" # 切换到新增/编辑标签页 tabs = self.dialog.findChild(QTabWidget) tabs.setCurrentIndex(1) # 填写表单 self.dialog.add_major_category.setCurrentText("布料") self.dialog.add_sub_category.setText("棉布") self.dialog.add_model.setText("GUI-TEST-001") self.dialog.add_supplier.setCurrentText("测试供应商") self.dialog.add_color.setText("白色") self.dialog.add_width.setValue(150.0) self.dialog.add_gsm.setValue(200.0) self.dialog.add_unit.setCurrentText("米") self.dialog.add_retail.setValue(10.0) self.dialog.add_bulk.setValue(8.0) # 点击保存按钮 self.dialog.save_raw_material() # 验证数据已保存到数据库 with self.dialog.get_conn() as conn: cursor = conn.execute("SELECT * FROM fabrics WHERE model = ?", ("GUI-TEST-001",)) row = cursor.fetchone() self.assertIsNotNone(row, "原料应该被保存到数据库") self.assertEqual(row[0], "GUI-TEST-001", "型号应该匹配") def test_add_raw_material_duplicate_model_gui(self): """测试通过GUI添加重复型号(应被拒绝)""" # 先添加一个原料 with self.dialog.get_conn() as conn: conn.execute(''' INSERT INTO fabrics (model, category, supplier, timestamp) VALUES (?, ?, ?, datetime('now')) ''', ("GUI-TEST-002", "布料", "供应商A")) conn.commit() # Mock warning消息框以捕获警告 warning_called = [] def mock_warning(*args, **kwargs): warning_called.append(args) QMessageBox.warning = mock_warning # 尝试添加重复型号 tabs = self.dialog.findChild(QTabWidget) tabs.setCurrentIndex(1) self.dialog.add_model.setText("GUI-TEST-002") self.dialog.add_major_category.setCurrentText("布料") self.dialog.save_raw_material() # 验证警告被触发 self.assertTrue(len(warning_called) > 0, "应该显示警告消息") # 验证数据库中只有一条记录 with self.dialog.get_conn() as conn: cursor = conn.execute("SELECT COUNT(*) FROM fabrics WHERE model = ?", ("GUI-TEST-002",)) count = cursor.fetchone()[0] self.assertEqual(count, 1, "数据库中应该只有一条记录") def test_add_raw_material_empty_model_gui(self): """测试通过GUI添加空型号(应被拒绝)""" warning_called = [] def mock_warning(*args, **kwargs): warning_called.append(args) QMessageBox.warning = mock_warning # 尝试保存空型号 tabs = self.dialog.findChild(QTabWidget) tabs.setCurrentIndex(1) self.dialog.add_model.setText("") self.dialog.save_raw_material() # 验证警告被触发 self.assertTrue(len(warning_called) > 0, "应该显示警告消息") # ========== 编辑原料GUI测试 ========== def test_edit_raw_material_gui(self): """测试通过GUI编辑原料""" # 先添加一个原料 with self.dialog.get_conn() as conn: conn.execute(''' INSERT INTO fabrics (model, category, supplier, color, timestamp) VALUES (?, ?, ?, ?, datetime('now')) ''', ("GUI-EDIT-001", "布料", "供应商A", "白色")) conn.commit() # 刷新表格 self.dialog.load_table() # 调用编辑方法 self.dialog.edit_raw_material("GUI-EDIT-001") # 验证表单已填充 self.assertEqual(self.dialog.add_model.text(), "GUI-EDIT-001") self.assertEqual(self.dialog.add_supplier.currentText(), "供应商A") self.assertEqual(self.dialog.add_color.text(), "白色") # 修改供应商 self.dialog.add_supplier.setCurrentText("供应商B") self.dialog.save_raw_material() # 验证修改已保存 with self.dialog.get_conn() as conn: cursor = conn.execute("SELECT supplier FROM fabrics WHERE model = ?", ("GUI-EDIT-001",)) row = cursor.fetchone() self.assertEqual(row[0], "供应商B", "供应商应该被更新") # ========== 删除原料GUI测试 ========== def test_delete_raw_material_gui(self): """测试通过GUI删除原料""" # 先添加一个原料 with self.dialog.get_conn() as conn: conn.execute(''' INSERT INTO fabrics (model, category, timestamp) VALUES (?, ?, datetime('now')) ''', ("GUI-DEL-001", "布料")) conn.commit() # 刷新表格 self.dialog.load_table() # 调用删除方法 self.dialog.delete_raw("GUI-DEL-001") # 验证已删除 with self.dialog.get_conn() as conn: cursor = conn.execute("SELECT * FROM fabrics WHERE model = ?", ("GUI-DEL-001",)) row = cursor.fetchone() self.assertIsNone(row, "原料应该被删除") # ========== 过滤和搜索GUI测试 ========== def test_filter_by_category_gui(self): """测试通过GUI按类目过滤""" # 添加测试数据 with self.dialog.get_conn() as conn: conn.execute(''' INSERT INTO fabrics (model, category, fabric_type, timestamp) VALUES (?, ?, ?, datetime('now')) ''', ("FILTER-001", "布料", "棉布")) conn.execute(''' INSERT INTO fabrics (model, category, fabric_type, timestamp) VALUES (?, ?, ?, datetime('now')) ''', ("FILTER-002", "辅料", "拉链")) conn.commit() # 刷新过滤器和表格 self.dialog.refresh_filters_and_table() # 选择"布料"类目 self.dialog.major_combo.setCurrentText("布料") # 验证表格只显示布料 row_count = self.dialog.table.rowCount() for row in range(row_count): category_item = self.dialog.table.item(row, 0) if category_item: self.assertEqual(category_item.text(), "布料", "应该只显示布料类目") def test_search_by_model_gui(self): """测试通过GUI搜索型号""" # 添加测试数据 with self.dialog.get_conn() as conn: conn.execute(''' INSERT INTO fabrics (model, category, timestamp) VALUES (?, ?, datetime('now')) ''', ("SEARCH-001", "布料")) conn.execute(''' INSERT INTO fabrics (model, category, timestamp) VALUES (?, ?, datetime('now')) ''', ("SEARCH-002", "布料")) conn.execute(''' INSERT INTO fabrics (model, category, timestamp) VALUES (?, ?, datetime('now')) ''', ("OTHER-001", "布料")) conn.commit() # 刷新表格 self.dialog.load_table() # 输入搜索关键词 self.dialog.search_input.setText("SEARCH") # 验证表格只显示匹配的结果 row_count = self.dialog.table.rowCount() for row in range(row_count): model_item = self.dialog.table.item(row, 2) if model_item: self.assertIn("SEARCH", model_item.text(), "应该只显示包含SEARCH的型号") if __name__ == "__main__": unittest.main()