Phoenix:控制器测试vs视图测试?

时间:2017-04-13 14:50:40

标签: elixir phoenix-framework

我有一个控制器:

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响应,然后将我控制器测试中当前的内容提取到视图测试中?或者这是测试事情的错误方法?

1 个答案:

答案 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查询隐藏在一个单独的方法中,你可以单独测试它以确保它真的只返回它应该返回的聚会,并且实际的视图测试可以在视图测试中完成:)