***

title: Testing
description: Test your agent thoroughly before production using local testing, swaig-test CLI, and test calls.
slug: /guides/testing
max-toc-depth: 3
---------------------

For a complete index of all SignalWire documentation pages, fetch https://signalwire.com/docs/llms.txt

### Testing Stages

#### 1. Local Testing

* Run agent locally
* Test with swaig-test CLI
* Verify SWML output

#### 2. Tunnel Testing

* Expose via ngrok
* Make real calls
* Test end-to-end

#### 3. Production Testing

* Deploy to production server
* Test with real phone
* Monitor call logs

### swaig-test CLI

Test agents without making calls:

```bash
# List available functions
swaig-test my_agent.py --list-tools

# View SWML output
swaig-test my_agent.py --dump-swml

# Execute a function
swaig-test my_agent.py --exec get_weather --city Seattle

# Raw JSON output
swaig-test my_agent.py --dump-swml --raw
```

### Local Server Testing

Run your agent locally using the appropriate command for your language:

| Language   | Start Command             |
| ---------- | ------------------------- |
| Python     | `python my_agent.py`      |
| TypeScript | `npx ts-node my_agent.ts` |

Then test the endpoint (the HTTP interface is identical regardless of language):

```bash
# In another terminal, test the endpoint (use credentials from agent output or env vars)
curl -X POST -u "$SWML_BASIC_AUTH_USER:$SWML_BASIC_AUTH_PASSWORD" http://localhost:3000/ \
  -H "Content-Type: application/json" \
  -d '{"call_id": "test-123"}'
```

### Using ngrok

Expose local server for real calls:

```bash
# Terminal 1: Run agent
python my_agent.py

# Terminal 2: Start ngrok
ngrok http 3000
```

Copy the ngrok HTTPS URL and configure in SignalWire.

### Test Call Checklist

#### Basic Functionality

* [ ] Call connects successfully
* [ ] Agent greeting plays
* [ ] Speech recognition works
* [ ] Agent responds appropriately

#### Function Calls

* [ ] Functions execute correctly
* [ ] Results returned to AI
* [ ] AI summarizes results properly

#### Edge Cases

* [ ] Silence handling
* [ ] Interruption handling
* [ ] Long responses
* [ ] Multiple function calls

#### Error Handling

* [ ] Invalid input handled
* [ ] Function errors handled gracefully
* [ ] Timeout behavior correct

### Viewing Logs

In SignalWire dashboard:

1. Go to [Logs](https://my.signalwire.com/?page=/logs/voices)
2. Find your test call
3. View details:
   * Call duration
   * SWML executed
   * Function calls
   * Errors

### Debugging with Logs

Add logging to your agent:

```python
import logging

logging.basicConfig(level=logging.DEBUG)

class MyAgent(AgentBase):
    def __init__(self):
        super().__init__(name="my-agent")
        self.log.info("Agent initialized")

    def my_handler(self, args, raw_data):
        self.log.debug(f"Function called with args: {args}")
        self.log.debug(f"Raw data: {raw_data}")

        result = "Some result"
        self.log.info(f"Returning: {result}")

        return FunctionResult(result)
```

### Testing Transfers

Test call transfers carefully. The transfer API is the same across languages via `FunctionResult`:

| Language   | Transfer Call                                                         |
| ---------- | --------------------------------------------------------------------- |
| Python     | `FunctionResult("Transferring").connect(number, final=True)`          |
| TypeScript | `new FunctionResult("Transferring").connect(number, { final: true })` |

```python
def test_transfer(self, args, raw_data):
    # Use a test number you control
    test_number = "+15551234567"

    return (
        FunctionResult("Transferring now")
        .connect(test_number, final=True)
    )
```

### Testing SMS

Test SMS sending. The SMS API follows the same pattern across languages:

| Language   | Send SMS                                                                            |
| ---------- | ----------------------------------------------------------------------------------- |
| Python     | `FunctionResult("Sent").send_sms(to_number=to, from_number=from_, body=msg)`        |
| TypeScript | `new FunctionResult("Sent").sendSms({ toNumber: to, fromNumber: from, body: msg })` |

```python
def test_sms(self, args, raw_data):
    # Send to your own phone for testing
    return (
        FunctionResult("Sent test SMS")
        .send_sms(
            to_number="+15551234567",  # Your test phone
            from_number="+15559876543", # Your SignalWire number
            body="Test message from agent"
        )
    )
```

### Load Testing

For production readiness:

* Test concurrent call handling
* Monitor server resources
* Check response times under load
* Verify function execution at scale
* Test database/API connection pooling

### Common Test Scenarios

| Scenario         | What to Test                 |
| ---------------- | ---------------------------- |
| Happy path       | Normal conversation flow     |
| No speech        | Silence and timeout handling |
| Background noise | Speech recognition accuracy  |
| Rapid speech     | Interruption handling        |
| Invalid requests | Error handling               |
| Function errors  | Graceful degradation         |
| Long calls       | Memory and stability         |

### Automated Testing

Create test scripts:

```python
import requests

def test_swml_endpoint():
    """Test that SWML endpoint returns valid response"""
    response = requests.post(
        "http://localhost:3000/",
        json={"call_id": "test-123"},
        headers={"Content-Type": "application/json"}
    )

    assert response.status_code == 200
    data = response.json()
    assert "version" in data
    assert data["version"] == "1.0.0"

def test_function_execution():
    """Test that functions execute correctly"""
    response = requests.post(
        "http://localhost:3000/swaig",
        json={
            "function": "get_weather",
            "argument": {"parsed": [{"city": "Seattle"}]},
            "call_id": "test-123"
        }
    )

    assert response.status_code == 200
```