简体   繁体   English

测试Flask应用程序时保留多种功能的更改

[英]Preserve changes in multiple function when testing a Flask app

I'm following a talk on Flask about creating an API. 我正在就Flask谈论创建API。 I want to write some tests for it. 我要为此编写一些测试。 Upon testing creating a resource does testing deleting the resource in another function work? 测试创建资源后,测试删除另一个功能中的资源是否有效? How do I make the creation of a resource persist to be tested for deletion and editing? 如何使资源的创建持续进行删除和编辑测试?

David Baumgold - Prototyping New APIs with Flask - PyCon 2016 David Baumgold-使用Flask制作新API的原型-PyCon 2016

The talk shows how to make an API for the names and image urls of puppies. 演讲显示了如何为小狗的名称和图像网址创建API。

  • you create a puppy at the index page with a POST request 您在POST请求的索引页上创建了一只小狗
  • you get a single puppy with a GET from '/puppy_name' 您会从'/ puppy_name'得到一只带GET的小狗
  • you get the list of puppies with a GET from '/' 您可以从“ /”获取带有GET的幼犬列表
  • you edit a puppy with a PUT from '/puppy_name' (along with the new data of course) 您可以使用“ / puppy_name”中的PUT编辑一条小狗(当然还有新数据)
  • you delete a puppy with a DELETE from '/puppy_name' 您从'/ puppy_name'删除了具有DELETE的小狗
import py.test
import unittest
from requests import get, post, delete, put

localhost = 'http://localhost:5000'

class TestApi(unittest.TestCase):
    def test_list_puppies(self):
        index = get(localhost)
        assert index.status_code == 200

    def test_get_puppy(self):
        puppy1 = get(localhost + '/rover')
        puppy2 = get(localhost + '/spot')
        assert puppy1.status_code == 200 and puppy2.status_code == 200

    def test_create_puppy(self):
        create = post(localhost, data={
            'name': 'lassie', 'image_url': 'lassie_url'})
        assert create.status_code == 201

    @py.test.mark.skip('cannot fix it')
    def test_edit_puppy(self):
        ret = put(localhost + '/lassie',
                  data={'name': 'xxx', 'image_url': 'yyy'})
        assert ret.status_code == 201

    def test_puppy_exits(self):
        lassie = get(localhost + '/lassie').status_code
        assert lassie == 200

    def test_delete_puppy(self):
        ret = delete(localhost + '/lassie')
        assert ret.status_code == 200
@app.route('/', methods=['POST'])
def create_puppy():
    puppy, errors = puppy_schema.load(request.form)
    if errors:
    response = jsonify(errors)
    response.status_code = 400
    return response

    puppy.slug = slugify(puppy.name)

    # create in database
    db.session.add(puppy)
    db.session.commit()

    # return an HTTP response
    response = jsonify( {'message': 'puppy created'} )
    response.status_code = 201
    location = url_for('get_puppy', slug=puppy.slug)
    response.headers['location'] = location

    return response

@app.route('/<slug>', methods=['DELETE'])
def delete_puppy(slug):
    puppy = Puppy.query.filter(Puppy.slug == slug).first_or_404()
    db.session.delete(puppy)
    db.session.commit()

    return jsonify( {'message': '{} deleted'.format(puppy.name)} )

The assert statements in both 'test_edit_puppy' and 'test_puppy_exists' fails. “ test_edit_puppy”和“ test_puppy_exists”中的assert语句均失败。 I get a 404 status code instead of 201 and 200. 我得到的是404状态代码,而不是201和200。

You're testing the wrong thing. 您正在测试错误的内容。 You can persist changes to a database, simply by committing it, when you run a test, but you really don't want to do that. 可以在运行测试时通过提交持久保存对数据库的更改,但是您确实不想这样做。

With unit testing you're testing simple units. 使用单元测试,您正在测试简单的单元。 With integration testing, which is what you're talking about here, you still want each test to have a specific focus. 对于集成测试,这就是您正在谈论的内容,您仍然希望每个测试都具有特定的重点。 In this particular case you would want to do something like: 在这种特殊情况下,您可能想要执行以下操作:

def test_delete_puppy(self):
    create = post(localhost, data={
        'name': 'lassie', 'image_url': 'lassie_url'})        
    lassie = get(localhost + '/lassie')

    # not sure if there's an "assume" method, but I would
    # use that here - the test is not a valid test
    # if you can't create a puppy and retrieve the puppy
    # then there's really no way to delete something that
    # does not exist
    assert create.status_code == 201
    assert lassie.status_code == 200

    ret = delete(localhost + '/lassie')
    assert ret.status_code == 200

    lassie = get(localhost + '/lassie')
    assert lassie.status_code == 404

The focus of this test is to test that deleting a puppy works fine. 该测试的重点是测试删除小狗是否正常。 But you want to setup the puppy in the database as either part of your test or part of the setup of your test. 但是您想在数据库中设置小狗作为测试的一部分或测试的一部分。 It's the arrange portion of arrange, act, assert . 这是arrange, act, assertarrange部分。 You're arranging the state of the world in its proper order before you actually perform the test. 在实际执行测试之前,您需要按正确的顺序排列世界状态。 The difference between integration testing and unit testing is that with unit testing you'd be mocking out all the endpoints that you're calling, while with integration tests you're going to actually setup all the data that you need before you run the test portion. 集成测试和单元测试之间的区别在于,使用单元测试,您将模拟要调用的所有端点,而使用集成测试,则将在运行测试之前实际设置所需的所有数据。一部分。 Which is what you want to do here. 您想在这里做什么。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM