LoginSignup
7
2

Elixir用AtCoderの自動テストをLivebookで実現できるか検討

Last updated at Posted at 2023-12-29

やりたいこと

LivebookにAtCoderの回答を書いて、テストボタンを押すと、問題にある入力例を入力して実行して、結果が正しいか判定する。
提出ボタンを押すと、回答が提出される

コマンドラインでは、この記事で紹介した方法でできてるんですが、Livebookでできたら、環境構築とかせず使えて面白そう。

要件

プログラムは変更せず、AtCoderに提出可能なものでテストを実行する。

必要な機能

  • 入力例、出力例をAtCoderから取得 →なんとかなるだろう(未調査)
  • stdioをfileにして実行 →課題
  • 結果の比較 →問題ない ExUintで実装

:stdioをfileにして実行する方法

コマンドラインで実行すれば何とでもできますが、Livebookで実現する方法が課題です。
次のような方法をとってみました。

  • MyIOを作って、IOの代わりにMyIOを使う。
  • MyIOは環境変数の設定で、deviceをstdioかファイル化を切り替える

Livebookで作ってみた

入力をそのまま返すプログラムを作って、テストしてみました。
回答プログラムは、AtCoderのコードテストでも変更なしで動作しました。

回答プログラム
defmodule Main do
  def input(), do: MyIO.read(:line) |> String.trim()

  def main() do
    s = input()
    MyIO.puts(s)
  end
end

defmodule MyIO do
  def read(_device \\ nil, option) do
    {file_in, _} = Application.get_env(:my_app, :file, {:stdio, :stdio})
    IO.read(file_in, option)
  end

  def puts(_device \\ nil, item) do
    {_, file_out} = Application.get_env(:my_app, :file, {:stdio, :stdio})
    IO.puts(file_out, item)
  end
end
テストプログラム
ExUnit.start(autorun: false)

defmodule MyTest do
  use ExUnit.Case, async: true

  test "test case 1" do
    {:ok, file} = File.open("in_1.txt", [:write])
    IO.write(file, "aaa\n")
    File.close(file)
    {:ok, file_in} = File.open("in_1.txt", [:read])
    {:ok, file_out} = File.open("out_1.txt", [:write])
    Application.put_env(:my_app, :file, {file_in, file_out})

    Main.main()

    File.close(file_out)
    {:ok, file_out} = File.open("out_1.txt", [:read])

    assert IO.read(file_out, :line) == "aaa\n"
  end
end

ExUnit.run()

今後の課題

  • MyIOを提出プログラムに追加しないといけない所がダサい。
  • MyIOがread,putsだけしか実装されてないので限定的だが、多くの問題には対応できるので、実用性はなくはない。
  • stdio自体をfileに置き換えれたら、任意のIO関数が使えて望ましいけど、不明。
  • Moxなどモックを実現する方法でIOを置き換える方法はどうか?

いい方法のコメントも歓迎です

7
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
2