import json import unittest from unittest.mock import patch, MagicMock from common.esigntool.main import ( _request, _build_alien_signer, _build_org_signer, get_auth_flow_id, get_template_detail, fill_in_template, get_contract_detail, create_by_file, sign_url, file_download_url, SIGN_FLOW_TITLES, SIGN_POSITIONS, TEMPLATE_COMPONENT_VALUES, ) from common.esigntool.esign_config import Config class TestConstants(unittest.TestCase): """模块级常量的完整性测试""" def test_sign_flow_titles_keys(self): expected = {"store_agreement", "alipay_auth", "wechat_pay_commitment", "lawyer_agreement"} self.assertEqual(set(SIGN_FLOW_TITLES.keys()), expected) def test_sign_positions_keys(self): expected = {"store_agreement", "alipay_auth", "wechat_pay_commitment", "lawyer_agreement"} self.assertEqual(set(SIGN_POSITIONS.keys()), expected) def test_template_component_values_keys(self): expected = {"store_agreement", "lawyer_agreement", "alipay_auth", "wechat_pay_commitment"} self.assertEqual(set(TEMPLATE_COMPONENT_VALUES.keys()), expected) def test_sign_positions_have_page_xy(self): for contract_type, positions in SIGN_POSITIONS.items(): for role, pos in positions.items(): with self.subTest(contract_type=contract_type, role=role): self.assertIn("page", pos, f"缺少 page: {contract_type}.{role}") self.assertIn("x", pos, f"缺少 x: {contract_type}.{role}") self.assertIn("y", pos, f"缺少 y: {contract_type}.{role}") class TestRequest(unittest.TestCase): """统一请求方法 _request 的测试""" @patch("common.esigntool.main.requests.request") @patch("common.esigntool.main.buildSignJsonHeader") def test_get_request_no_body(self, mock_build_header, mock_req): mock_build_header.return_value = {"X-Test": "header"} mock_resp = MagicMock() mock_resp.text = '{"code":0}' mock_req.return_value = mock_resp result = _request("GET", "/v3/test") mock_build_header.assert_called_once() mock_req.assert_called_once_with( "GET", "https://smlopenapi.esign.cn/v3/test", headers={"X-Test": "header"}, ) self.assertEqual(result, '{"code":0}') @patch("common.esigntool.main.requests.request") @patch("common.esigntool.main.buildSignJsonHeader") def test_post_request_with_body(self, mock_build_header, mock_req): mock_build_header.return_value = {"X-Test": "header"} mock_resp = MagicMock() mock_resp.text = '{"code":0,"data":{}}' mock_req.return_value = mock_resp body = {"name": "test", "value": 123} result = _request("POST", "/v3/action", body) mock_req.assert_called_once() call_args = mock_req.call_args[0] call_kwargs = mock_req.call_args[1] self.assertEqual(call_args[0], "POST") self.assertEqual(call_args[1], "https://smlopenapi.esign.cn/v3/action") self.assertEqual(call_kwargs["headers"], {"X-Test": "header"}) sent_data = json.loads(call_kwargs["data"]) self.assertEqual(sent_data, body) self.assertEqual(result, '{"code":0,"data":{}}') class TestBuildAlienSigner(unittest.TestCase): """平台方签署人构建测试""" def test_returns_correct_structure(self): position = {"page": 1, "x": 100, "y": 200} result = _build_alien_signer("file_123", position) self.assertEqual(result["signConfig"]["signOrder"], 1) self.assertEqual(result["signerType"], 1) self.assertEqual(len(result["signFields"]), 1) field = result["signFields"][0] self.assertEqual(field["customBizNum"], "9527") self.assertEqual(field["fileId"], "file_123") self.assertTrue(field["normalSignFieldConfig"]["autoSign"]) pos = field["normalSignFieldConfig"]["signFieldPosition"] self.assertEqual(pos["positionPage"], "1") self.assertEqual(pos["positionX"], 100) self.assertEqual(pos["positionY"], 200) class TestBuildOrgSigner(unittest.TestCase): """签署方(商家/律所)签署人构建测试""" def test_returns_correct_structure(self): position = {"page": 3, "x": 50, "y": 100} result = _build_org_signer("file_456", position, "测试公司", "91110000MA0001", "13800138000", "张三") self.assertEqual(result["signConfig"]["signOrder"], 2) self.assertEqual(result["signConfig"]["forcedReadingTime"], 10) self.assertEqual(result["signerType"], 1) self.assertEqual(result["orgSignerInfo"]["orgName"], "测试公司") self.assertEqual(result["orgSignerInfo"]["orgInfo"]["orgIDCardNum"], "91110000MA0001") self.assertEqual(result["orgSignerInfo"]["transactorInfo"]["psnAccount"], "13800138000") self.assertEqual(result["orgSignerInfo"]["transactorInfo"]["psnInfo"]["psnName"], "张三") field = result["signFields"][0] self.assertEqual(field["customBizNum"], "自定义编码001") self.assertEqual(field["fileId"], "file_456") pos = field["normalSignFieldConfig"]["signFieldPosition"] self.assertEqual(pos["positionPage"], "3") self.assertEqual(pos["positionX"], 50) self.assertEqual(pos["positionY"], 100) class TestGetAuthFlowId(unittest.TestCase): """获取机构认证链接测试""" @patch("common.esigntool.main._request") def test_calls_request_with_correct_params(self, mock_request): mock_request.return_value = '{"code":0}' result = get_auth_flow_id("测试公司", "91110000MA0001", "张三", "110101199001011234") print(result) mock_request.assert_called_once_with("POST", "/v3/org-auth-url", unittest.mock.ANY) call_body = mock_request.call_args[0][2] self.assertEqual(call_body["orgAuthConfig"]["orgName"], "测试公司") self.assertEqual(call_body["orgAuthConfig"]["orgInfo"]["orgIDCardNum"], "91110000MA0001") self.assertEqual(call_body["orgAuthConfig"]["orgInfo"]["legalRepName"], "张三") self.assertEqual(call_body["orgAuthConfig"]["orgInfo"]["legalRepIDCardNum"], "110101199001011234") self.assertTrue(call_body["transactorUseSeal"]) self.assertEqual(result, '{"code":0}') class TestGetTemplateDetail(unittest.TestCase): """查询模板详情测试""" @patch("common.esigntool.main._request") def test_calls_request_with_get(self, mock_request): mock_request.return_value = '{"code":0}' config = Config() get_template_detail() mock_request.assert_called_once_with("GET", f"/v3/doc-templates/{config.templates_id}") class TestFillInTemplate(unittest.TestCase): """填写模板测试""" @patch("common.esigntool.main._request") def test_store_agreement_components(self, mock_request): mock_request.return_value = '{"code":0}' config = Config() fill_in_template("测试店铺", "store_agreement") call_body = mock_request.call_args[0][2] self.assertEqual(call_body["docTemplateId"], config.templates_map["store_agreement"]) self.assertEqual(call_body["fileName"], config.template_file_names["store_agreement"]) component_keys = {c["componentKey"] for c in call_body["components"]} self.assertIn("store_name", component_keys) self.assertIn("one_name", component_keys) self.assertIn("date", component_keys) self.assertIn("alien_name", component_keys) @patch("common.esigntool.main._request") def test_lawyer_agreement_components(self, mock_request): mock_request.return_value = '{"code":0}' config = Config() fill_in_template("测试律所", "lawyer_agreement") call_body = mock_request.call_args[0][2] component_keys = {c["componentKey"] for c in call_body["components"]} self.assertIn("law_firm_name", component_keys) self.assertIn("law_firm_name_2", component_keys) self.assertIn("signing_date", component_keys) @patch("common.esigntool.main._request") def test_default_contract_type(self, mock_request): mock_request.return_value = '{"code":0}' fill_in_template("测试") call_body = mock_request.call_args[0][2] self.assertEqual(call_body["fileName"], "U店在这-商户入驻协议") class TestGetContractDetail(unittest.TestCase): """查询合同文件测试""" @patch("common.esigntool.main._request") def test_calls_with_file_id(self, mock_request): mock_request.return_value = '{"code":0}' get_contract_detail("abc123") mock_request.assert_called_once_with("GET", "/v3/files/abc123") class TestCreateByFile(unittest.TestCase): """基于文件发起签署测试""" @patch("common.esigntool.main._request") def test_store_agreement_has_both_signers(self, mock_request): mock_request.return_value = '{"code":0}' create_by_file( "file_001", "测试协议", "测试公司", "91110000MA0001", "13800138000", "张三", "store_agreement" ) call_body = mock_request.call_args[0][2] self.assertEqual(len(call_body["signers"]), 2) self.assertEqual(call_body["signFlowConfig"]["signFlowTitle"], "商家入驻U店平台协议签署") self.assertEqual(call_body["docs"][0]["fileId"], "file_001") self.assertEqual(call_body["docs"][0]["fileName"], "测试协议.pdf") @patch("common.esigntool.main._request") def test_wechat_only_signer(self, mock_request): mock_request.return_value = '{"code":0}' create_by_file( "file_002", "承诺函", "测试公司", "91110000MA0002", "13900139000", "李四", "wechat_pay_commitment" ) call_body = mock_request.call_args[0][2] self.assertEqual(len(call_body["signers"]), 1) self.assertEqual(call_body["signFlowConfig"]["signFlowTitle"], "微信支付承诺函签署") @patch("common.esigntool.main._request") def test_default_contract_type(self, mock_request): mock_request.return_value = '{"code":0}' create_by_file("file_003", "文件", "公司", "id001", "13800000000", "王五") call_body = mock_request.call_args[0][2] self.assertEqual(len(call_body["signers"]), 2) self.assertEqual(call_body["signFlowConfig"]["signFlowTitle"], "商家入驻U店平台协议签署") @patch("common.esigntool.main._request") def test_auto_finish_enabled(self, mock_request): mock_request.return_value = '{"code":0}' create_by_file("f", "n", "c", "id", "phone", "name") call_body = mock_request.call_args[0][2] self.assertTrue(call_body["signFlowConfig"]["autoFinish"]) self.assertEqual(call_body["signFlowConfig"]["noticeConfig"]["noticeTypes"], "1,2") class TestSignUrl(unittest.TestCase): """获取签署链接测试""" @patch("common.esigntool.main._request") def test_calls_with_flow_id_and_account(self, mock_request): mock_request.return_value = '{"code":0}' sign_url("flow_abc", "13800138000") call_body = mock_request.call_args[0][2] self.assertEqual(call_body["signFlowId"], "flow_abc") self.assertEqual(call_body["operator"]["psnAccount"], "13800138000") self.assertFalse(call_body["needLogin"]) self.assertEqual(call_body["urlType"], 2) self.assertEqual(call_body["clientType"], "ALL") class TestFileDownloadUrl(unittest.TestCase): """下载文件链接测试""" @patch("common.esigntool.main._request") def test_calls_with_flow_id(self, mock_request): mock_request.return_value = '{"code":0}' file_download_url("flow_xyz") mock_request.assert_called_once_with( "POST", "/v3/sign-flow/flow_xyz/file-download-url", {"urlAvailableDate": "3600"} ) if __name__ == "__main__": unittest.main()