HTTP 测试

未匹配的标注

在你发起并调试一个请求的时候可能会用到 get , post , put , patch , delete 等方法. 而这些方法其实并不会真的发起一个 HTTP 请求到你的应用程序. 而是返回了一个 MasonitResponse 类的对象,测试请求方法返回一个 HTTPTestResponse 实例,它提供了各种有用的断言,允许你检查和断言应用程序的响应。

def test_basic_request(self):
    self.get("/").assertOk()

获取请求和响应

通过访问 requestresponse 属性可以获取测试的请求和响应。

def test_request_and_response(self):
    request = self.get('/testing').request # <masonite.requests.Request>
    response = self.get('/testing').response # <masonite.response.Response>

注册路由

在调试期间,可以使用 addRoutes() 方法注册仅用于测试目的的路由。例如:

@classmethod
def setUpClass(cls):
    super().setUpClass()
    cls.addRoutes(
        Route.get("/", "TestController@show"),
        Route.post("/", "TestController@show"),
    )

路由查重

要检查路由是否存在,我们可以简单地使用 getpost

def test_route_exists(self):
    self.assertTrue(self.get('/testing'))
    self.assertTrue(self.post('/testing'))

请求头

在发送请求之前你可能需要用到 withHeaders() 方法在自定义请求的头部信息. 这个方法让你能够以字典类型的形式添加任何你想要的请求头:

request = self.withHeaders({"X-TEST": "value"}).get("/").request
self.assertEqual(request.header("X-Test"), "value")

请求的Cookies

可以使用 withCookies() 方法来设置 cookie 的值,跟 withHeaders() 方法一样,这个方法的参数需要是形式为键值对的字典:

self.withCookies({"test": "value"}).get("/").assertCookie("test", "value")

身份认证

如果要在测试中发出经过身份验证的请求,可以使用 actingAs() 方法
获取给定的 User 记录,并在请求期间对其进行身份验证。

user = User.find(1)
self.actingAs(user).get("/")

还可以指定认证守卫 来验证具有特定权限的用户:

user = User.find(1)
self.actingAs(user, "web").get("/")

用户将仅在测试的生命周期内保持。测试期间提出的每个请求将与给定用户进行身份验证。当然如果你想要注销该用户,可以使用 actingAsGuest() 方法:

def test_auth(self):
    user = User.find(1)
    self.actingAs(user).get("/home")

    self.actingAsGuest().get("/about")

CSRF保护

默认情况下,使用上述方法对路由的所有调用都不会受 CSRF 保护。测试代码将允许你绕过该保护。
这非常有用,因为不必担心在每个请求上设置 CSRF 令牌,但也有可能会希望启用该保护。那么就可以通过在调试中调用 withCsrf() 方法来启用。

def test_csrf(self):
    self.withCsrf()
    self.post("/unit/test/json", {"test": "testing"})

一般是在特定测试上启用它,但如果希望在所有测试上启用,可以通过将该方法添加到 setUp() 方法中来实现:

def setUp(self):
    super().setUp()
    self.withCsrf()

也可以使用 withoutCsrf() 方法停止启用。

异常处理

正如你所注意到的,Masonite 具有异常处理功能,在开发过程中使用它来显示有用的信息。

在应用程序调试期间,我们往往会希望看到更多有用的调试相关问题。因此,一般情况下会默认禁用 Masonite 的异常处理,以便在测试期间看到更多有用的异常。如果想使用 Masonite 内置的异常处理,可以参考下面的示例:

def setUp(self):
    super().setUp()
    self.withExceptionHandling()

你也可以向下面这样来禁用 Masonite 的异常处理:

def test_something(self):
    self.withExceptionHandling()
    self.get("/").assertUnauthorized()
    self.withoutExceptionHandling()
    self.get("/")

很多可用的断言调试方法

Masonite 提供了多种断言方法,用于在测试应用程序时检查和验证请求/响应逻辑。这些方法适用于 get , post , put , patch , delete 等方法请求的 HTTPTestResponse

assertContains

断言返回的响应包含给定的 content 字符串。注意,如果需要,响应内容将最终被解码。

self.get("/").assertContains(content)

assertNotContains

断言返回的响应不包含给定的 content。注意,如果需要,响应内容将最终被解码。

self.get("/").assertNotContains(content)

assertContainsInOrder

断言返回的响应按顺序包含给定的字符串。注意,如果需要,响应内容将最终被解码。

self.get("/").assertContains(string1, string2, ...)

assertNoContent

断言返回的响应没有内容和给定的 HTTP 状态码。断言的默认状态码是 204 。

self.get("/").assertNoContent(status=204)

assertIsNamed

断言给定的路由具有给定的名称。

self.get("/").assertIsNamed("home")

assertIsNotNamed

断言给定的路由没有给定的名称。

self.get("/").assertIsNotNamed("admin")

assertIsStatus

断言响应具有给定的 HTTP 状态码:

self.get("/").assertIsStatus(201)

assertOk

断言响应返回 200 状态码:

self.get("/").assertOk()

assertCreated

断言响应返回 201 状态码:

self.get("/").assertCreated()

assertSuccessful

断言响应具有 200 到 300 之间的状态码。

self.get("/").assertSuccessful()

assertUnauthorized

断言响应具有 401 状态码。

self.get("/").assertUnauthorized()

assertForbidden

断言响应具有 403 状态码。

self.get("/").assertForbidden()

assertError

断言响应具有 500 状态码。

self.get("/").assertError()

assertHasHeader

断言响应具有给定的标头名称和值(如果给定)。

self.get("/").assertHasHeader(name, value=None)

assertHeaderMissing

断言响应没有给定的标头。

self.get("/").assertHeaderMissing(name)

assertLocation

断言在 Location 标头中具有给定的 URI 值。

self.get("/").assertLocation(uri)

assertRedirect

断言是重定向到给定的 URI(如果提供)或者是对带有给定参数的给定路由名的重定向(如果提供)。

self.get("/logout").assertRedirect(url=None, name=None, params={})
self.get("/logout").assertRedirect()
self.get("/logout").assertRedirect("/login")
self.get("/login").assertRedirect(name="profile", params={"user": 1})

assertCookie

断言包含给定的 cookie 名称和值(如果提供)。

self.get("/").assertCookie(name, value=None)

assertPlainCookie

断言包含给定的未加密 cookie 名称

self.get("/").assertPlainCookie(name)

assertCookieExpired

断言请求包含给定的 cookie 名称并已过期。

self.get("/").assertCookieExpired(name)

assertCookieMissing

断言请求不包含给定的 cookie

self.get("/").assertCookieMissing(name)

assertSessionHas

断言请求包含给定的键和值(如果提供)。

self.get("/").assertSessionHas(name, value=None)

assertSessionMissing

断言请求不包含给定的键。

self.get("/").assertSessionMissing(name)

assertSessionHasErrors

断言包含一个 errors 键或在 errors 键中包含给定的键列表。

self.get("/").assertSessionHasErrors()
self.get("/").assertSessionHasErrors(["email", "first_name"])

assertSessionHasNoErrors

断言不包含 errors 键或该键为空。

self.get("/").assertSessionHasNoErrors()

assertViewIs

断言路由返回给定的视图名。

self.get("/").assertViewIs("app")

assertViewHas

断言视图上下文包含给定的数据键和值(如果提供)。

self.get("/").assertViewHas(key, value=None)

assertViewHasExact

断言视图上下文包含给定的数据键。它可以是一个键列表或一个字典(这里只验证键)。

self.get("/").assertViewHasExact(keys)

assertViewMissing

断言给定的数据键在视图上下文中不可用。

self.get("/").assertViewMissing(key)

assertAuthenticated

断言用户在当前请求之后进行了身份验证。

self.get("/login").assertAuthenticated()

如果给定一个用户实例,它将断言该用户已经过身份验证:

user = User.find(1)
self.get("/login").assertAuthenticated(user)

也可以指定认证守卫来检查给定守卫上的身份验证状态。

self.get("/api/login").assertAuthenticated(user, "jwt")

assertGuest

断言用户在当前请求之后没有进行身份验证。

self.get("/").assertGuest()

也可以指定认证守卫来检查给定守卫上的身份验证状态。

assertHasHttpMiddleware

断言请求具有给定的 HTTP 中间件。应该提供 HTTP 中间件类。

self.get("/").assertHasHttpMiddleware(middleware_class)
from app.middleware import MyAppMiddleware
self.get("/").assertHasHttpMiddleware(MyAppMiddleware)

assertHasRouteMiddleware

断言请求具有给定的路由中间件。应该提供中间件的注册密钥。

self.get("/").assertHasRouteMiddleware(middleware_name)
# route_middleware = {"web": [SessionMiddleware, VerifyCsrfToken]}
self.get("/").assertHasRouteMiddleware("web")

assertHasController

断言路由使用了给定的控制器。可以提供一个类或字符串。如果它是一个字符串,它应该被格式化为 ControllerName@method

self.get("/").assertHasController(controller)
from app.controllers import WelcomeController
self.get("/").assertHasController(WelcomeController)
self.get("/").assertHasController("WelcomeController@index")

assertRouteHasParameter

断言所使用的路由具有给定的参数名称和值(如果提供)。

self.get("/").assertRouteHasParameter(key, value=None)

assertJson

断言响应是 JSON 并包含给定的数据字典(如果提供)。即使不是精确匹配,断言也会通过。

self.get("/").assertJson(data={})
self.get("/").assertJson()  # check that response is JSON
self.get("/").assertJson({"key": "value", "other": "value"})

assertJsonPath

断言响应是 JSON 并包含给定的路径,如果提供了最终的给定值。路径可以是点路径。

self.get("/").assertJsonPath(path, value=None)
self.get("/").assertJsonPath("user.profile.name", "John")

assertJsonExact

断言响应是 JSON ,并且严格等于给定的字典。

self.get("/").assertJsonExact(data)

assertJsonCount

断言该响应是 JSON ,并且在根级别上具有给定数量的键或给定的键(如果提供)。

self.get("/").assertJsonCount(count, key=None)

assertJsonMissing

断言该响应是 JSON ,并且不包含给定的路径。路径可以是点路径。

self.get("/").assertJsonMissing(path)

测试期间打印数据

在单元测试期间,getpostputpatch、 或 delete 返回的 HTTPTestResponse 上提供了方便的 dumpdd 帮助程序。

dumpRequestHeaders

从请求中获得测试响应后,你可以通过将此 helper 链接到响应中,将请求头打印到控制台中:

self.get("/register").assertRedirect().dumpRequestHeaders().assertSessionHas("success")

dumpResponseHeaders

从请求中获取测试响应后,你可以在控制台中打印响应标头:

self.get("/").dumpResponseHeaders()

ddHeaders

从请求中获取测试响应后,你可以在控制台中打印响应和请求头并停止执行测试:

self.get("/register").assertRedirect().ddHeaders().assertSessionHas("success")

这里 assertSessionHas 不会被执行,因为测试会在执行之前停止。

dumpSession

从请求中获得测试响应后,你可以通过将此 helper 链接到响应来将会话数据打印到控制台中:

self.get("/register").assertRedirect().dumpSession().assertSessionHas("success")

ddSession

从请求中获得测试响应后,你可以将会话数据打印到控制台并停止执行测试:

self.get("/register").assertRedirect().ddSession().assertSessionHas("success")

这里 assertSessionHas 不会被执行,因为测试会在执行之前停止。

在你发起并调试一个请求的时候可能会用到get,post,put,patch,delete等方法. 而这些方法其实并不会真的发起一个HTTP请求到你的应用程序. 而是返回了一个Masonit的Response类的对象,测试请求方法返回一个HTTPTestResponse实例,它提供了各种有用的断言,允许您检查和断言应用程序的响应。

def test_basic_request(self):
    self.get("/").assertOk()

获取请求和响应

通过访问requestresponse属性可以获取测试的请求和响应。

def test_request_and_response(self):
    request = self.get('/testing').request # <masonite.requests.Request>
    response = self.get('/testing').response # <masonite.response.Response>

注册路由

在调试期间,可以使用addRoutes()方法注册仅用于测试目的的路由。例如:

@classmethod
def setUpClass(cls):
    super().setUpClass()
    cls.addRoutes(
        Route.get("/", "TestController@show"),
        Route.post("/", "TestController@show"),
    )

路由查重

要检查路由是否存在,我们可以简单地使用getpost:

def test_route_exists(self):
    self.assertTrue(self.get('/testing'))
    self.assertTrue(self.post('/testing'))

请求头

在发送请求之前你可能需要用到withHeaders()方法在自定义请求的头部信息. 这个方法让你能够以字典dict类型的形式添加任何你想要的请求头:

request = self.withHeaders({"X-TEST": "value"}).get("/").request
self.assertEqual(request.header("X-Test"), "value")

请求的Cookies

可以使用withCookies()方法来设置cookie的值,跟withHeaders()方法一样,这个方法的参数需要是形式为键值对的字典:

self.withCookies({"test": "value"}).get("/").assertCookie("test", "value")

身份认证

如果要在测试中发出经过身份验证的请求,可以使用actingAs()方法
获取给定的User记录,并在请求期间对其进行身份验证。

user = User.find(1)
self.actingAs(user).get("/")

还可以指定authentication guard 来验证具有特定权限的用户:

user = User.find(1)
self.actingAs(user, "web").get("/")

用户将仅在测试的生命周期内保持。测试期间提出的每个请求将与给定用户进行身份验证.当然如果你想要注销该用户,可以使用 actingAsGuest()方法:

def test_auth(self):
    user = User.find(1)
    self.actingAs(user).get("/home")

    self.actingAsGuest().get("/about")

CSRF保护

默认情况下,使用上述方法对路由的所有调用都不会受CSRF保护。测试代码将允许您绕过该保护。
这非常有用,因为不必担心在每个请求上设置CSRF令牌,但也有可能会希望启用该保护。那么就可以通过在调试中调用withCsrf()方法来启用。

def test_csrf(self):
    self.withCsrf()
    self.post("/unit/test/json", {"test": "testing"})

一般是在特定测试上启用它,但如果希望在所有测试上启用,可以通过将该方法添加到setUp()方法中来实现:

def setUp(self):
    super().setUp()
    self.withCsrf()

也可以使用withoutCsrf()方法停止启用.

异常处理

正如你所注意到的,Masonite具有异常处理功能,在开发过程中使用它来显示有用的信息。

在应用程序调试期间,我们往往会希望看到更多有用的调试相关问题。因此,一般情况下会默认禁用Masonite的异常处理,以便在测试期间看到更多有用的异常。如果想使用Masonite内置的异常处理,可以参考下面的示例:

def setUp(self):
    super().setUp()
    self.withExceptionHandling()

你也可以向下面这样来禁用Masonite的异常处理:

def test_something(self):
    self.withExceptionHandling()
    self.get("/").assertUnauthorized()
    self.withoutExceptionHandling()
    self.get("/")

很多可用的断言调试方法

Masonite提供了多种断言方法,用于在测试应用程序时检查和验证请求/响应逻辑. 这些方法适用于get, post, put, patch,delete等方法请求的HTTPTestResponse.

assertContains

Assert that returned response contains the given content string. Note that the response content will be eventually decoded if required.

self.get("/").assertContains(content)

assertNotContains

Assert that returned response does not contain the given content string. Note that the response content will be eventually decoded if required.

self.get("/").assertNotContains(content)

assertContainsInOrder

Assert that returned response contains in order the given strings. Note that the response content will be eventually decoded if required.

self.get("/").assertContains(string1, string2, ...)

assertNoContent

Assert that returned response has no content and the given HTTP status code. The default status code that is asserted is 204.

self.get("/").assertNoContent(status=204)

assertIsNamed

Assert that given route has the given name.

self.get("/").assertIsNamed("home")

assertIsNotNamed

Assert that given route has not the given name.

self.get("/").assertIsNotNamed("admin")

assertIsStatus

Assert that the response has the given HTTP status code:

self.get("/").assertIsStatus(201)

assertOk

Assert that the response returns a 200 status code:

self.get("/").assertOk()

assertCreated

Assert that the response returns a 201 status code:

self.get("/").assertCreated()

assertSuccessful

Assert that the response has as status code between 200 and 300

self.get("/").assertSuccessful()

assertUnauthorized

Assert that the response has as 401 status code

self.get("/").assertUnauthorized()

assertForbidden

Assert that the response has as 403 status code

self.get("/").assertForbidden()

assertError

Assert that the response has as 500 status code

self.get("/").assertError()

assertHasHeader

Assert that the response has the given header name and value (if given).

self.get("/").assertHasHeader(name, value=None)

assertHeaderMissing

Assert that the response does not have the given header.

self.get("/").assertHeaderMissing(name)

assertLocation

Assert the response has the given URI value in Location header.

self.get("/").assertLocation(uri)

assertRedirect

Assert that the response is a redirection to the given URI (if provided) or to the given route name with the given parameters (if provided).

self.get("/logout").assertRedirect(url=None, name=None, params={})
self.get("/logout").assertRedirect()
self.get("/logout").assertRedirect("/login")
self.get("/login").assertRedirect(name="profile", params={"user": 1})

assertCookie

Assert that the request contains the given cookie name and value (if provided).

self.get("/").assertCookie(name, value=None)

assertPlainCookie

Assert that the request contains the given unencrypted cookie name

self.get("/").assertPlainCookie(name)

assertCookieExpired

Assert that the request contains the given cookie name and is expired.

self.get("/").assertCookieExpired(name)

assertCookieMissing

Assert that the request does not contain the given cookie.

self.get("/").assertCookieMissing(name)

assertSessionHas

Assert that the session contains the given key and value (if provided).

self.get("/").assertSessionHas(name, value=None)

assertSessionMissing

Assert that the session does not contain the given key.

self.get("/").assertSessionMissing(name)

assertSessionHasErrors

Assert that the session contains an errors key or contains the given list of keys in errors key.

self.get("/").assertSessionHasErrors()
self.get("/").assertSessionHasErrors(["email", "first_name"])

assertSessionHasNoErrors

Assert that the session does not contain an errors key or that this key is empty.

self.get("/").assertSessionHasNoErrors()

assertViewIs

Assert that the route returned the given view name.

self.get("/").assertViewIs("app")

assertViewHas

Assert that view context contains a given data key and value (if provided).

self.get("/").assertViewHas(key, value=None)

assertViewHasExact

Assert that view context contains exactly the given data keys. It can be a list of keys or a dictionary (here only keys will be verified).

self.get("/").assertViewHasExact(keys)

assertViewMissing

Assert that given data key is not available in the view context.

self.get("/").assertViewMissing(key)

assertAuthenticated

Assert that a user is authenticated after the current request.

self.get("/login").assertAuthenticated()

If a user instance is given it will assert that this user is authenticated:

user = User.find(1)
self.get("/login").assertAuthenticated(user)

The authentication guard can also be specified to check the
authentication state on the given guard.

self.get("/api/login").assertAuthenticated(user, "jwt")

assertGuest

Assert that a user is not authenticated after the current request.

self.get("/").assertGuest()

The authentication guard can also be specified to check the
authentication state on the given guard.

assertHasHttpMiddleware

Assert that the request has the given HTTP middleware. An HTTP middleware class should be provided.

self.get("/").assertHasHttpMiddleware(middleware_class)
from app.middleware import MyAppMiddleware
self.get("/").assertHasHttpMiddleware(MyAppMiddleware)

assertHasRouteMiddleware

Assert that the request has the given route middleware. The registration key of the middleware should be provided.

self.get("/").assertHasRouteMiddleware(middleware_name)
# route_middleware = {"web": [SessionMiddleware, VerifyCsrfToken]}
self.get("/").assertHasRouteMiddleware("web")

assertHasController

Assert that the route used the given controller. A class or a string can be provided. If it's a string it should be formatted as follow ControllerName@method.

self.get("/").assertHasController(controller)
from app.controllers import WelcomeController
self.get("/").assertHasController(WelcomeController)
self.get("/").assertHasController("WelcomeController@index")

assertRouteHasParameter

Assert that the route used has the given parameter name and value (if provided).

self.get("/").assertRouteHasParameter(key, value=None)

assertJson

Assert that response is JSON and contains the given data dictionary (if provided). The assertion will pass even if it is not an exact match.

self.get("/").assertJson(data={})
self.get("/").assertJson()  # check that response is JSON
self.get("/").assertJson({"key": "value", "other": "value"})

assertJsonPath

Assert that response is JSON and contains the given path, with eventually the given value if provided. The path can be a dotted path.

self.get("/").assertJsonPath(path, value=None)
self.get("/").assertJsonPath("user.profile.name", "John")

assertJsonExact

Assert that response is JSON and is strictly equal to the given dictionary.

self.get("/").assertJsonExact(data)

assertJsonCount

Assert that response is JSON and has the given count of keys at root level or at the given key (if provided).

self.get("/").assertJsonCount(count, key=None)

assertJsonMissing

Assert that response is JSON and does not contain given path. The path can be a dotted path.

self.get("/").assertJsonMissing(path)

Dump Data During Tests

Handy dump and dd helpers are available on the HTTPTestResponse returned by get, post, put, patch, or delete during a
unit test.

dumpRequestHeaders

After getting a test response back from a request you can dump request headers in console by
chaining this helper to the response:

self.get("/register").assertRedirect().dumpRequestHeaders().assertSessionHas("success")

dumpResponseHeaders

After getting a test response back from a request you can dump response headers in console:

self.get("/").dumpResponseHeaders()

ddHeaders

After getting a test response back from a request you can dump response and request headers in console and stop the
test execution:

self.get("/register").assertRedirect().ddHeaders().assertSessionHas("success")

Here assertSessionHas will not be executed as the test will be stopped before.

dumpSession

After getting a test response back from a request you can dump session data in console by
chaining this helper to the response:

self.get("/register").assertRedirect().dumpSession().assertSessionHas("success")

ddSession

After getting a test response back from a request you can dump session data in console and stop the
test execution:

self.get("/register").assertRedirect().ddSession().assertSessionHas("success")

Here assertSessionHas will not be executed as the test will be stopped before.

在测试期间,您可以注册仅用于测试目的的路由。你可以用
`addR

本文章首发在 LearnKu.com 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://learnku.com/docs/masonite/4.0/te...

译文地址:https://learnku.com/docs/masonite/4.0/te...

上一篇 下一篇
贡献者:3
讨论数量: 0
发起讨论 只看当前版本


暂无话题~