Files
agent-desktop/tests/unit/channels
..
2026-08-23 22:44:18 +08:00

Channel Testing Guide

Testing Architecture

tests/
├── contract/channels/          # ⭐ Contract Tests (Required)
│   ├── __init__.py            # ChannelContractTest base class
│   ├── test_console_contract.py   # Simple Channel reference
│   ├── test_dingtalk_contract.py  # Complex Channel reference
│   ├── test_feishu_contract.py    # Complex Channel reference
│   └── test_*_contract.py         # All 11 Channels covered (0 missing)
│
└── unit/channels/              # Unit Tests (All Channels)
    ├── README.md               # This file
    ├── test_base_core.py       # BaseChannel internal logic (68 tests)
    ├── test_console.py         # ConsoleChannel unit tests (26 tests)
    ├── test_dingtalk.py        # DingTalkChannel unit tests (159 tests)
    ├── test_discord.py         # DiscordChannel unit tests (55 tests)
    ├── test_feishu.py          # FeishuChannel unit tests (120 tests)
    ├── test_imessage.py        # IMessageChannel unit tests (37 tests)
    ├── test_matrix.py          # MatrixChannel unit tests (55 tests)
    ├── test_mattermost.py      # MattermostChannel unit tests (82 tests)
    ├── test_mqtt.py            # MQTTChannel unit tests (50 tests)
    ├── test_onebot_channel.py  # OneBotChannel unit tests (53 tests)
    ├── test_qq.py              # QQChannel unit tests (116 tests)
    ├── test_telegram.py        # TelegramChannel unit tests (93 tests)
    ├── test_voice.py           # VoiceChannel unit tests (37 tests)
    ├── test_wecom.py           # WecomChannel unit tests (69 tests)
    ├── test_wechat.py          # WeChatChannel unit tests (78 tests)
    └── test_xiaoyi.py          # XiaoyiChannel unit tests (57 tests)

Contract Tests vs Unit Tests

Type Location Purpose Status
Contract Tests tests/contract/channels/ Verify external interface compatibility 128 tests, CI hard gate
Unit Tests tests/unit/channels/ Verify internal logic correctness 1200+ tests, CI enforcement

Both test types are required to pass in CI.

Unit Test Coverage by Channel

Channel Test Count Lines Complexity Status
BaseChannel (Core) 68 1,390 Core Logic Complete
DingTalk 159 3,708 High Complete
Feishu 120 2,652 High Complete
QQ 116 2,096 High Complete
Telegram 93 1,798 Medium-High Complete
Mattermost 82 1,990 Medium-High Complete
WeChat 78 1,617 Medium Complete
Wecom 69 1,504 Medium Complete
Base (test_base_core.py) 68 1,390 Core Complete
Console 26 567 Simple Complete
Xiaoyi 57 1,219 Medium Complete
Discord 55 945 Medium Complete
Matrix 55 1,068 Medium Complete
OneBot 53 756 Medium Complete
MQTT 50 922 Medium Complete
IMessage 37 1,007 Simple-Medium Complete
Voice 37 651 Simple Complete

Total: 1,200+ unit tests across 16 test files

Local Development

# Run all contract tests (required)
pytest tests/contract/channels/ -v

# Run all unit tests
pytest tests/unit/channels/ -v

# Run specific Channel unit tests
pytest tests/unit/channels/test_dingtalk.py -v
pytest tests/unit/channels/test_feishu.py -v

# Run with coverage
pytest tests/unit/channels/ \
    --cov=src/copaw/app/channels \
    --cov-report=term-missing

# Check contract coverage status
make check-contracts

Adding New Channel Tests

For Contract Tests

All Channels already have contract tests. To add a new Channel:

# 1. Copy the official template
cp tests/contract/channels/test_console_contract.py \
   tests/contract/channels/test_yourchannel_contract.py

# 2. Modify class name and create_instance()

# 3. Local verification
make check-contracts  # Should show your Channel in tested list

For Unit Tests

Create a new test file following the existing pattern:

# tests/unit/channels/test_yourchannel.py
"""Unit tests for YourChannel implementation."""

import pytest
from src.copaw.app.channels.your_channel import YourChannel


class TestYourChannel:
    """Test suite for YourChannel."""

    def test_initialization(self):
        """Test channel can be initialized."""
        channel = YourChannel()
        assert channel is not None

    def test_start_stop(self):
        """Test channel lifecycle."""
        # Implementation here
        pass

    # Add more tests...

CI/CD Integration

All tests run in the CI pipeline with the following gates:

Phase Test Type Threshold Gate Type Status
1 Contract Tests 100% (128/128) 🔴 Hard Gate ⚠️ Temporarily skipped (Pydantic issue)
2 Unit Tests All must pass 🔴 Hard Gate Active
3 Coverage Minimum threshold 🟡 Soft Gate Non-blocking with warnings

Hard Gate: Failure blocks PR merge Soft Gate: Warning only, non-blocking (continue-on-error)

Four-Layer Protection (Contract Tests)

Layer 1: Abstract Method Check
├── test_no_abstract_methods_remaining
└── Catches: BaseChannel adds @abstractmethod

Layer 2: Instantiation Check
├── test_no_abstractmethods__in_instance
└── Catches: Cannot create instance (unimplemented methods)

Layer 3: Method Override Check
├── test_required_methods_not_raising_not_implemented
└── Catches: Method still raises NotImplementedError

Layer 4: Signature Compatibility Check
├── test_start_method_signature_compatible
├── test_stop_method_signature_compatible
├── test_resolve_session_id_signature_compatible
└── Catches: Method signature changes break subclasses

Current Status

📊 Channel Contract Test Coverage
   Total Channels: 11
   With Contract Tests: 12
   Missing: 0
   Contract Tests: 128 passing

📊 Channel Unit Test Coverage
   Total Channels: 11
   With Unit Tests: 11
   Missing: 0
   Unit Tests: 1,200+ passing

✅ All Channels fully covered:
   ConsoleChannel, DingTalkChannel, FeishuChannel,
   DiscordChannel, IMessageChannel, MQTTChannel,
   MatrixChannel, MattermostChannel, QQChannel,
   TelegramChannel, VoiceChannel

🎉 Zero missing tests - both contract and unit tests complete!

Core Principles

  1. Contract tests are primary - Must pass in CI (hard gate)
  2. Unit tests are required - Must pass in CI (hard gate)
  3. All Channels have full coverage - Both contract and unit tests
  4. Four-layer protection - Effective prevention against "fix Console breaks DingTalk"
  5. Breaking tests = blocking PR - CI gates ensure quality

Quick Reference

Command Purpose
make check-contracts Show contract coverage status
pytest tests/contract/channels/ -v Run all contract tests
pytest tests/unit/channels/ -v Run all unit tests
pytest tests/unit/channels/test_dingtalk.py -v Run specific Channel tests
pytest tests/unit/channels/ -k "test_init" Run specific test pattern

📖 中文版本

📋 Related: PR #2506 - Test infrastructure and coverage baseline establishment