Initial commit: 知识库管理器应用

- 实现基于 PySide6 的 GUI 界面
- 集成 FastAPI 知识库服务器 API
- 支持查看、编辑、提交 Markdown 文件
- 包含完整的 pytest-qt 测试套件
- 添加功能列表文档
This commit is contained in:
2026-01-30 12:03:12 +08:00
commit 0ab3d4f9c1
10 changed files with 695 additions and 0 deletions

180
test_app.py Normal file
View File

@@ -0,0 +1,180 @@
import pytest
from PySide6.QtWidgets import QApplication, QMessageBox
from PySide6.QtCore import Qt
from unittest.mock import Mock, patch
from main_window import KnowledgeBaseApp
@pytest.fixture(scope="module")
def app():
"""创建 QApplication 实例"""
if not QApplication.instance():
app = QApplication([])
else:
app = QApplication.instance()
yield app
@pytest.fixture
def main_window(app, qtbot):
"""创建主窗口实例"""
window = KnowledgeBaseApp()
qtbot.addWidget(window)
window.show()
return window
def test_window_initialization(main_window, qtbot):
"""测试窗口初始化"""
assert main_window.windowTitle() == '知识库管理器'
assert main_window.server_input.text() == 'http://43.134.1.17:8800/'
assert main_window.config_button.text() == '配置'
assert main_window.refresh_button.text() == '刷新列表'
assert main_window.save_button.text() == '保存到服务器'
assert main_window.post_button.text() == '提交新文件'
def test_server_input_exists(main_window, qtbot):
"""测试服务器地址输入框"""
assert main_window.server_input is not None
assert main_window.server_input.placeholderText() == ''
qtbot.keyClicks(main_window.server_input, 'http://test.com')
assert 'http://test.com' in main_window.server_input.text()
def test_filename_input_exists(main_window, qtbot):
"""测试文件名输入框"""
assert main_window.filename_input is not None
assert main_window.filename_input.placeholderText() == '输入文件名例如example.md'
qtbot.keyClicks(main_window.filename_input, 'test.md')
assert main_window.filename_input.text() == 'test.md'
def test_text_editor_exists(main_window, qtbot):
"""测试文本编辑器"""
assert main_window.text_editor is not None
test_content = '# Test Markdown\n\nThis is a test.'
main_window.text_editor.setPlainText(test_content)
assert main_window.text_editor.toPlainText() == test_content
def test_file_list_exists(main_window):
"""测试文件列表"""
assert main_window.file_list is not None
assert main_window.file_list.count() == 0
def test_buttons_clickable(main_window, qtbot):
"""测试按钮可点击"""
assert main_window.config_button.isEnabled()
assert main_window.refresh_button.isEnabled()
assert main_window.save_button.isEnabled()
assert main_window.post_button.isEnabled()
def test_configure_server_without_url(main_window, qtbot):
"""测试配置服务器无URL"""
main_window.server_input.clear()
with patch.object(QMessageBox, 'warning') as mock_warning:
main_window.configure_server()
mock_warning.assert_called_once()
assert main_window.api is None
def test_configure_server_invalid_url(main_window, qtbot):
"""测试配置服务器无效URL"""
main_window.server_input.setText('http://invalid-url-that-does-not-exist.com')
with patch.object(QMessageBox, 'critical') as mock_critical:
main_window.configure_server()
mock_critical.assert_called_once()
def test_refresh_file_list_without_api(main_window, qtbot):
"""测试刷新文件列表(未配置服务器)"""
main_window.api = None
with patch.object(QMessageBox, 'warning') as mock_warning:
main_window.refresh_file_list()
mock_warning.assert_called_once()
def test_save_file_without_api(main_window, qtbot):
"""测试保存文件(未配置服务器)"""
main_window.api = None
with patch.object(QMessageBox, 'warning') as mock_warning:
main_window.save_file()
mock_warning.assert_called_once()
def test_save_file_without_selection(main_window, qtbot):
"""测试保存文件(未选择文件)"""
main_window.api = Mock()
main_window.current_filename = None
with patch.object(QMessageBox, 'warning') as mock_warning:
main_window.save_file()
mock_warning.assert_called_once()
def test_post_new_file_without_api(main_window, qtbot):
"""测试提交新文件(未配置服务器)"""
main_window.api = None
with patch.object(QMessageBox, 'warning') as mock_warning:
main_window.post_new_file()
mock_warning.assert_called_once()
def test_post_new_file_without_filename(main_window, qtbot):
"""测试提交新文件(无文件名)"""
main_window.api = Mock()
main_window.filename_input.clear()
with patch.object(QMessageBox, 'warning') as mock_warning:
main_window.post_new_file()
mock_warning.assert_called_once()
def test_post_new_file_without_content(main_window, qtbot):
"""测试提交新文件(无内容)"""
main_window.api = Mock()
main_window.filename_input.setText('test.md')
main_window.text_editor.clear()
with patch.object(QMessageBox, 'warning') as mock_warning:
main_window.post_new_file()
mock_warning.assert_called_once()
def test_post_new_file_auto_add_extension(main_window, qtbot):
"""测试提交新文件(自动添加.md扩展名"""
main_window.api = Mock()
main_window.filename_input.setText('test')
main_window.text_editor.setPlainText('# Test')
with patch.object(QMessageBox, 'information') as mock_info:
with patch.object(main_window, 'refresh_file_list'):
main_window.post_new_file()
assert main_window.filename_input.text() == 'test.md'
def test_ui_layout_elements(main_window):
"""测试UI布局元素"""
assert main_window.server_input.parent() is not None
assert main_window.file_list.parent() is not None
assert main_window.text_editor.parent() is not None
assert main_window.status_label.parent() is not None
def test_status_label_updates(main_window, qtbot):
"""测试状态标签更新"""
initial_text = main_window.status_label.text()
main_window.status_label.setText('测试状态')
assert main_window.status_label.text() == '测试状态'
if __name__ == '__main__':
pytest.main([__file__, '-v'])