File size: 6,325 Bytes
116524e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
# Testing

## Running Tests

=== "pytest (recommended)"

    ```bash

    uv run pytest                         # All tests

    uv run pytest -m unit                 # Unit tests only

    uv run pytest -m integration          # Integration tests only

    uv run pytest tests/test_skillbook.py # Specific file

    uv run pytest -v                      # Verbose output

    ```


=== "unittest"

    ```bash

    python -m unittest discover -s tests

    python -m unittest discover -s tests -v  # Verbose

    ```


## Testing Without API Calls

Use a mock LLM to test pipeline wiring without making real API calls. Any object with `complete()` and `complete_structured()` methods satisfies the `LLMClientLike` protocol:

```python

from unittest.mock import MagicMock

from ace import Agent, Reflector, SkillManager



mock_llm = MagicMock()

mock_llm.complete.return_value = '{"reasoning": "test", "final_answer": "4", "skill_ids": []}'



agent = Agent(mock_llm)

reflector = Reflector(mock_llm)

skill_manager = SkillManager(mock_llm)

```

## Unit Testing

### Testing the Skillbook

```python

from ace import Skillbook



def test_add_skill():

    skillbook = Skillbook()

    skill = skillbook.add_skill(

        section="Test",

        content="Test strategy",

        metadata={"helpful": 0, "harmful": 0, "neutral": 0},

    )

    assert len(skillbook.skills()) == 1

    assert skill.content == "Test strategy"



def test_save_load(tmp_path):

    skillbook = Skillbook()

    skillbook.add_skill(section="Test", content="Strategy")



    path = str(tmp_path / "test.json")

    skillbook.save_to_file(path)



    loaded = Skillbook.load_from_file(path)

    assert len(loaded.skills()) == 1

```

### Testing the Agent

```python

from unittest.mock import MagicMock

from ace import Agent, Skillbook



def test_agent_generate():

    mock_llm = MagicMock()

    mock_llm.complete.return_value = '{"reasoning": "2+2=4", "final_answer": "4", "skill_ids": []}'



    agent = Agent(mock_llm)

    output = agent.generate(

        question="What is 2+2?",

        context="",

        skillbook=Skillbook(),

    )

    assert output.final_answer is not None

    assert output.reasoning is not None

```

### Testing Reflector and SkillManager

```python

from unittest.mock import MagicMock

from ace import Agent, Reflector, SkillManager, Skillbook



def make_mock_llm():

    mock = MagicMock()

    mock.complete.return_value = '{"reasoning": "test", "final_answer": "4", "skill_ids": []}'

    return mock



def test_reflector():

    mock_llm = make_mock_llm()

    reflector = Reflector(mock_llm)

    agent = Agent(mock_llm)



    output = agent.generate(question="Test", context="", skillbook=Skillbook())

    reflection = reflector.reflect(

        question="Test",

        agent_output=output,

        skillbook=Skillbook(),

        ground_truth="expected",

        feedback="Correct",

    )

    assert reflection.key_insight is not None



def test_skill_manager():

    sm = SkillManager(make_mock_llm())

    # ... similar pattern with reflection input

```

## Integration Testing

### End-to-End Learning Cycle

```python

from unittest.mock import MagicMock

from ace import (

    ACE, Agent, Reflector, SkillManager,

    Sample, SimpleEnvironment,

)



def test_full_learning_cycle():

    mock_llm = MagicMock()

    mock_llm.complete.return_value = '{"reasoning": "test", "final_answer": "answer", "skill_ids": []}'



    runner = ACE.from_roles(

        agent=Agent(mock_llm),

        reflector=Reflector(mock_llm),

        skill_manager=SkillManager(mock_llm),

        environment=SimpleEnvironment(),

    )



    samples = [Sample(question="Test", context="", ground_truth="answer")]

    results = runner.run(samples, epochs=1)



    assert len(results) == 1

```

### Testing Checkpoints

```python

def test_checkpoints(tmp_path):

    mock_llm = MagicMock()

    mock_llm.complete.return_value = '{"reasoning": "test", "final_answer": "A", "skill_ids": []}'



    runner = ACE.from_roles(

        agent=Agent(mock_llm),

        reflector=Reflector(mock_llm),

        skill_manager=SkillManager(mock_llm),

        environment=SimpleEnvironment(),

        checkpoint_dir=str(tmp_path),

        checkpoint_interval=1,

    )



    samples = [Sample(question="Q", context="", ground_truth="A")]

    runner.run(samples, epochs=1)



    # Check that checkpoint files were created

    checkpoints = list(tmp_path.glob("ace_*.json"))

    assert len(checkpoints) > 0

```

## Common Test Patterns

### Fixtures

```python

import pytest

from unittest.mock import MagicMock

from ace import Agent, Reflector, SkillManager, Skillbook



@pytest.fixture

def mock_llm():

    mock = MagicMock()

    mock.complete.return_value = '{"reasoning": "test", "final_answer": "4", "skill_ids": []}'

    return mock



@pytest.fixture

def skillbook():

    return Skillbook()



@pytest.fixture

def agent(mock_llm):

    return Agent(mock_llm)

```

### Mocking LLM Responses

```python

from unittest.mock import MagicMock



def test_with_mock():

    mock_llm = MagicMock()

    mock_llm.complete.return_value = '{"reasoning": "...", "final_answer": "4", "skill_ids": []}'



    agent = Agent(mock_llm)

    # ...

```

## CI Configuration

```yaml

# .github/workflows/test.yml

name: Tests

on: [push, pull_request]

jobs:

  test:

    runs-on: ubuntu-latest

    steps:

      - uses: actions/checkout@v4

      - uses: astral-sh/setup-uv@v4

      - run: uv sync

      - run: uv run pytest -v

```

## Code Quality

```bash

uv run black ace/ tests/ examples/     # Format

uv run mypy ace/                       # Type check

uv run pre-commit run --all-files      # All hooks

```

## Troubleshooting

| Problem | Solution |
|---------|----------|
| Import errors | Run `uv sync` to install all dependencies |
| API key errors in tests | Use `MagicMock` for unit tests (see above) |
| Flaky async tests | Increase timeout or use `wait_for_background()` |
| Coverage too low | `--cov-fail-under=25` is the threshold |

## What to Read Next

- [Full Pipeline Guide](full-pipeline.md) — what you're testing
- [Async Learning](async-learning.md) — testing async pipelines