DEV Community

Weerasak Chongnguluam
Weerasak Chongnguluam

Posted on • Updated on

ใช้ ExMachina ช่วยเตรียมข้อมูลสำหรับ test ของ Elixir

ExMachina เป็น library ที่ช่วยให้เราจัดเตรียมข้อมูลสำหรับทดสอบให้แยกออกมาอยู่ที่เดียวกัน ทำให้โค้ดที่เขาเขียนเทสจริงๆไม่รกและเราเอาสิ่งที่แยกมาไปใช้ได้ในหลายๆเทสเคสได้

การจะใช้งาน ExMachina ขั้นแรกเราเพิ่ม dependency ให้กับ mix.exs ของเราก่อนแบบนี้

{:ex_machina, "~> 2.5.0"}
Enter fullscreen mode Exit fullscreen mode

เราสามารถเขียนโค้ดของ module ที่เป็น Factory module ในการจัดเตรียม test data ไว้ที่ไหนก็ได้ แต่จาก document ของ ExMachina เนี่ยแนะนำว่าให้เอาไว้ที่ test/support directory

แต่ว่าพอเอาไว้ในนี้ต้องไม่ลืมเพิ่ม elixir_paths ให้กับ application config ของ mix.exs ด้วยไม่งั้น compiler มันจะไม่ compile โค้ดในนี้ เรา config แบบนี้

  def project do
    [
      app: :ecto_sample,
      version: "0.1.0",
      elixir: "~> 1.11",
      start_permanent: Mix.env() == :prod,
      deps: deps(),
      # ตรงนี้ให้ไปเรียก `elixir_paths` เพื่อ config ขึ้นอยู่กับแต่ละ Mix.env
      elixirc_paths: elixirc_paths(Mix.env()), ()
      aliases: aliases()
    ]
  end

  # ถ้าเป็น :test env ก็ให้ compile ของใน `test/support` ด้วย
  defp elixirc_paths(:test), do: ["lib", "test/support"]
  defp elixirc_paths(_), do: ["lib"]
Enter fullscreen mode Exit fullscreen mode

ส่วนวิธีการเขียนโค้ด factory module นั้นก็ง่ายๆคือให้สร้าง module แล้ว use ExMachina หรือ ExMachina.Ecto ถ้าเราใช้เตรียมข้อมูลให้กับ Ecto Schema โดยต้อง config repo module ให้ด้วย

จากนั้นก็สร้าง function ที่ลงท้ายด้วย _factory ซึ่งจะเป็นฟังก์ชันที่เราไปใช้กับ build, insert method ของ ExMachina ได้ ตัวอย่างเช่น

defmodule EctoSample.Factory do
  use ExMachina.Ecto, repo: EctoSample.Repo

  def post_factory do
    %EctoSample.Post{
      title: "Sample use ExMachina",
      body: "Example to prepare fixture data for testing"
    }
  end
end
Enter fullscreen mode Exit fullscreen mode

ผมก็เขียนฟังก์ชัน post_factory ซึ่งก็แค่เตรียมข้อมูลของ EctoSample.Post schema เอาไว้ ทีนี้ตอนใช้งานใน test case สิ่งที่เราทำก็คือใช้ ExMachina ฟังก์ชันอย่าง build เพื่อสร้างค่าตาม factory function หรือใช้ insert เพื่อ insert ค่าลง DB ตาม factory function ตัวอย่างเช่น

defmodule EctoSampleTest do
  use ExUnit.Case

  # ต้อง import factory module ที่ต้องการใช้เข้ามาก่อน
  import EctoSample.Factory

  test "build post by ExMachina Factory" do
    post = build(:post)
    {:ok, post} = EctoSample.Repo.insert(post)
    assert post.title == "Sample use ExMachina"
    assert post.body == "Example to prepare fixture data for testing"
  end

  test "insert post by ExMachina Factory" do
    post = insert(:post)
    assert post.title == "Sample use ExMachina"
    assert post.body == "Example to prepare fixture data for testing"
  end
end
Enter fullscreen mode Exit fullscreen mode

ซึ่งค่าที่ส่งให้ build กับ insert ก็คือชื่อของ factory ชื่อของฟังก์ชันที่อยู่ก่อนคำว่า _factory นั่นเอง

ทีนี้ถ้าเทสเคสของเรามีข้อมูลที่ต้องการปรับจากค่าที่เตรียมไว้ใน factory ทั้ง insert และ build สามารถรับค่า key: value เพิ่มไปได้เพื่อเปลี่ยนแค่บาง field เช่นอ

  test "insert post by ExMachina Factory with title Hello ExMachina" do
    post = insert(:post, title: "Hello ExMachina")
    assert post.title == "Hello ExMachina"
    assert post.body == "Example to prepare fixture data for testing"
  end
Enter fullscreen mode Exit fullscreen mode

สรุป ExMachina ช่วยทำให้การจัดเตรียมข้อมูลสำหรับเทสนั้นเป็นสัดส่วนและดูแลง่าย และทำให้โค้ดในส่วนการเทสจริงๆไม่รกเต็มไปด้วยโค้ดในการเตรียมข้อมูลที่ซ้ำซ้อนเวลาเปลี่ยนทีก็ยากแบบก่อนที่จะใช้ ExMachina ช่วยนั่นเอง

Buy Me A Coffee

Top comments (0)