我有一个控制器:
defmodule ParrotApi.MeetupController do
use ParrotApi.Web, :controller
alias ParrotApi.Meetup
def index(conn, _params) do
one_hour_ago = Timex.now
|> Timex.shift(hours: -1)
|> Timex.to_unix
meetups = from(m in Meetup, where: m.timestamp >= ^one_hour_ago)
|> Repo.all
|> Repo.preload(:topic)
render conn, meetups: meetups
end
end
以及该控制器的视图:
defmodule ParrotApi.MeetupView do
use ParrotApi.Web, :view
def render("index.json", %{ meetups: meetups }) do
render_many(meetups, ParrotApi.MeetupView, "meetup.json")
end
def render("meetup.json", %{ meetup: meetup }) do
%{
id: meetup.id,
timestamp: meetup.timestamp,
topic: meetup.topic.title,
}
end
end
我正在编写我的第一个控制器测试:
defmodule ParrotApi.MeetupControllerTest do
use ParrotApi.ConnCase
alias ParrotApi.Meetup
alias ParrotApi.Topic
alias ParrotApi.Repo
require Logger
describe "#index" do
test "returns future meetups" do
topic_title = "Is Jesus your savior?"
future_time = Timex.now
|> Timex.shift(minutes: 1)
|> Timex.to_unix
{:ok, topic} = Topic.changeset(%Topic{}, %{title: topic_title}) |> Repo.insert
{:ok, meetup} = Meetup.changeset(%Meetup{}, %{timestamp: future_time, topic_id: topic.id}) |> Repo.insert
conn = build_conn()
conn = get conn, meetup_path(conn, :index)
assert json_response(conn, 200) == [
%{
"id" => meetup.id,
"timestamp" => future_time,
"topic" => topic_title,
}
]
end
它过去了。但是......这对我来说感觉像是一种观察测试?它正在测试视图操作的装饰/呈现响应。所以我真的不知道该怎么做我的观看测试。
有没有办法只测试render conn, meetups: meetups
响应,然后将我控制器测试中当前的内容提取到视图测试中?或者这是测试事情的错误方法?
答案 0 :(得分:1)
虽然我认为测试最佳实践很多是关于开发人员的意见和偏见,但我非常同意您的测试正在测试一些超出其职责范围的内容,并且应该在视图测试中测试实际的JSON结构。
就个人而言,我更喜欢测试json响应的内容以及控制器测试中的响应状态,但是你的测试对“jsons结构如何”而不是“内容是什么”做出了非常强烈的假设。
您通常会将json创建保留给json创建者(您的视图)并且只关心“控制器是否呈现它应该呈现的内容?”
如果我被要求用一句话总结最重要的测试内容,那就是:“在脑海中制定你想要测试的内容,然后尝试让你的测试代码完全像那样读取”。所以基本上我想要我的测试就是这样:
我期待所有未来聚会的状态代码为200的json编码响应。
test "returns future meetups" do
topic_title = "Is Jesus your savior?"
future_time = Timex.now
|> Timex.shift(minutes: 1)
|> Timex.to_unix
{:ok, topic} = Topic.changeset(%Topic{}, %{title: topic_title}) |> Repo.insert
{:ok, meetup} = Meetup.changeset(%Meetup{}, %{timestamp: future_time, topic_id: topic.id}) |> Repo.insert
conn = build_conn()
conn = get conn, meetup_path(conn, :index)
future_meetups_json = MeetupView.render("index.json", %{meetups: MeetupQuery.future_meetups()})
assert conn.status == 200
assert conn.response_body == future_meetups_json
end
将meetup查询隐藏在一个单独的方法中,你可以单独测试它以确保它真的只返回它应该返回的聚会,并且实际的视图测试可以在视图测试中完成:)