DEV Community

Weerasak Chongnguluam
Weerasak Chongnguluam

Posted on • Edited 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

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (0)