# 如何设计与数据上下文无关的接口测试用例




我们在做接口测试的时候很可能设计出这样与数据关联的测试用例。比如

```python
def test_create_user(self):
  user = create_user(name="fred", age=29) # 调用创建用户的接口
  self.assertEqual(user['name'], 'fred')

def test_get_user(self):
  user = get_last_created_user() #调用获取最新注册用户的接口
  self.assertEqual(user['name'], 'fred')
```

这样的测试用例第一眼看上去是感受不出来问题的。

不过仔细想想，可能会存在下面的问题

* ```test_create_user```用例必须在```test_get_user```用例执行之前执行，否则```test_get_user(self)```用户是没有数据的，* ``` test_get_user```用例没办法单独执行
* ```test_create_user```用例执行一次之后，```name: fred, age: 29```就成了脏数据了，不删除的话之后```test_get_user```用例有很大概率每次都能执行成功

为了解决上面的问题，我们可以这样做

```python
def test_create_user(self):
  user = create_user(name="fred", age=29) # 调用创建用户的接口
  delete_user(user['id']) # 调用删除接口，将创建的用户给删除掉
  self.assertEqual(user['name'], 'fred')

def test_get_user(self):
  user = create_user(name="fred", age=29) # 调用创建用户的接口
  user = get_last_created_user() #调用获取最新注册用户的接口
  delete_user(user['id']) # 调用删除接口，将创建的用户给删除掉
  self.assertEqual(user['name'], 'fred')
```

这样一来脏数据问题就解决了，不过用例里多了很多跟测试逻辑无关的代码。

顺便留一个问题给大家思考：为什么删除数据的代码要放在断言之前执行？

为了将数据处理代码跟测试逻辑分开来，下一步我们可以这样做，以sqlite3为例

```python
import sqlite3

def setUp(self):
  conn = sqlite3.connect('example.db')
  c = conn.cursor()
  c.execute("delete * from users")
  c.execute("insert into users ......") # 插入一些存量数据，这样测试翻页之类的逻辑会容易点
  conn.commit()
  conn.close()

def test_create_user(self):
  user = create_user(name="fred", age=29) # 调用创建用户的接口
  self.assertEqual(user['name'], 'fred')

def test_get_user(self):
  user = create_user(name="fred", age=29) # 调用创建用户的接口
  user = get_last_created_user() #调用获取最新注册用户的接口
  self.assertEqual(user['name'], 'fred')
```

上面的例子里，```setUp```方法会在每个用例执行之前执行，所以就不需要每条用例都去清理数据了。

### 总结

* 上面的例子都是以unittest库为例，其他测试框架库原理是相同的
* 上面的例子是伪代码，不能直接执行
* 上面的例子里，每个用例执行之前都会插入一遍数据，如果数据量比较大，那么用例运行速度会变慢




原始封面

![课程图片](https://images.unsplash.com/photo-1501854140801-50d01698950b?w=300)


