til/gpt3/writing-test-with-copilot.md
# Writing tests with Copilot
I needed to write a relatively repetitive collection of tests, for a number of different possible error states.
The code I was testing [looks like this](https://github.com/simonw/datasette/blob/187d91d68617ca48e34c1fb0c6722a40f8567d45/datasette/views/database.py#L561-L687):
```python
columns = data.get("columns")
rows = data.get("rows")
row = data.get("row")
if not columns and not rows and not row:
return _error(["columns, rows or row is required"])
if rows and row:
return _error(["Cannot specify both rows and row"])
if columns:
if rows or row:
return _error(["Cannot specify columns with rows or row"])
if not isinstance(columns, list):
return _error(["columns must be a list"])
for column in columns:
if not isinstance(column, dict):
return _error(["columns must be a list of objects"])
if not column.get("name") or not isinstance(column.get("name"), str):
return _error(["Column name is required"])
if not column.get("type"):
column["type"] = "text"
if column["type"] not in self._supported_column_types:
return _error(
["Unsupported column type: {}".format(column["type"])]
)
# No duplicate column names
dupes = {c["name"] for c in columns if columns.count(c) > 1}
if dupes:
return _error(["Duplicate column name: {}".format(", ".join(dupes))])
```
I wanted to write tests for each of the error cases. I'd already constructed the start of a parameterized `pytest` test for these.
I got Copilot/GPT-3 to write most of the tests for me.
First I used VS Code to select all of the `_error(...)` lines. I pasted those into a new document and turned them into a sequence of comments, like this:
```python
# Error: columns must be a list
# Error: columns must be a list of objects
# Error: Column name is required
# Error: Unsupported column type
# Error: Duplicate column name
# Error: rows must be a list
# Error: rows must be a list of objects
# Error: pk must be a string
```
I pasted those comments into my test file inside the existing list of parameterized tests, then wrote each test by adding a newline beneath a comment and hitting `tab` until Copilot had written the test for me.
It correctly guessed both the error assertion and the desired invalid input for each one!
Here's an animated screenshot:

The [finished tests are here](https://github.com/simonw/datasette/blob/187d91d68617ca48e34c1fb0c6722a40f8567d45/tests/test_api_write.py#L548-L722).