Tauri 앱은 Rust 코어와 웹 프런트엔드가 함께 움직이므로 테스트도 층을 나눠 생각하는 것이 좋습니다. 이 장에서는 Rust 단위 테스트, IPC를 흉내 낸 프런트엔드 테스트, 실제 앱 창을 조작하는 WebDriver 기반 E2E 테스트를 차례로 다룹니다.
Rust 단위 테스트
#[tauri::command]가 붙은 함수도 평범한 Rust 함수이므로 테스트에서 바로 부를 수 있습니다. 다만 명령 안에 로직을 많이 넣기보다, 순수 함수로 떼어 두고 명령은 그 함수를 부르는 얇은 층으로 두면 테스트가 훨씬 쉬워집니다.
// src-tauri/src/lib.rs
fn normalize_title(title: &str) -> String {
title.trim().to_string()
}
#[tauri::command]
fn divide(a: f64, b: f64) -> Result<f64, String> {
if b == 0.0 {
return Err("0으로 나눌 수 없습니다".into());
}
Ok(a / b)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn trims_title() {
assert_eq!(normalize_title(" 장보기 "), "장보기");
}
#[test]
fn divide_by_zero_is_error() {
assert!(divide(1.0, 0.0).is_err());
assert_eq!(divide(9.0, 3.0), Ok(3.0));
}
}
테스트는 src-tauri 폴더에서 실행합니다. 저장소 루트에서 돌리려면 매니페스트 경로를 넘깁니다.
cd src-tauri && cargo test
# 또는 저장소 루트에서
cargo test --manifest-path src-tauri/Cargo.toml
State나 AppHandle을 받는 명령까지 IPC 경로 그대로 확인하고 싶다면, tauri 크레이트의 test 기능을 켜고 tauri::test 모듈의 모의 런타임(mock_builder, mock_context, noop_assets)으로 창 없이 앱을 만들어 시험할 수 있습니다.
프런트엔드 테스트: IPC 흉내 내기
일반 브라우저나 jsdom에는 Tauri 코어가 없으므로 invoke가 그대로는 동작하지 않습니다. @tauri-apps/api/mocks의 mockIPC로 명령 응답을 흉내 내면, 화면 코드를 Vitest나 Jest로 시험할 수 있습니다. Vitest 설정에서 environment를 "jsdom"으로 둡니다.
// src/greet.test.ts
import { afterEach, beforeAll, expect, test } from "vitest";
import { randomFillSync } from "node:crypto";
import { clearMocks, mockIPC } from "@tauri-apps/api/mocks";
import { invoke } from "@tauri-apps/api/core";
beforeAll(() => {
// jsdom에는 WebCrypto 구현이 없어 채워 줍니다
Object.defineProperty(window, "crypto", {
value: { getRandomValues: (buffer: any) => randomFillSync(buffer) },
});
});
// 테스트마다 흉내 낸 상태를 지웁니다
afterEach(() => clearMocks());
test("greet 명령 응답을 흉내 낸다", async () => {
mockIPC((cmd, args) => {
if (cmd === "greet") return `안녕하세요, ${(args as { name: string }).name}님!`;
});
await expect(invoke("greet", { name: "Tauri" })).resolves.toBe("안녕하세요, Tauri님!");
});
같은 모듈의 mockWindows로 창 라벨을 흉내 낼 수도 있습니다. 화면이 어떤 인자로 명령을 부르는지 확인하려면 mockIPC 안에서 받은 args를 기록해 두고 검사합니다.
E2E 테스트: WebDriver
빌드된 앱을 실제로 띄워 버튼을 누르고 결과를 확인하려면 W3C 표준인 WebDriver를 씁니다. 공식 문서가 권하는 방법은 WebdriverIO의 Tauri 서비스(@wdio/tauri-service)입니다. npm create wdio@latest ./에서 Desktop Testing과 Tauri를 고르면 설정이 만들어집니다. 기본 방식(embedded)은 앱 안에 WebDriver 서버를 넣는 tauri-plugin-wdio-webdriver 플러그인을 쓰며, Windows · Linux · macOS에서 모두 동작합니다. 이 플러그인은 테스트용 빌드에만 넣도록 구성하는 것이 좋습니다.
// wdio.conf.ts
export const config: WebdriverIO.Config = {
specs: ["./e2e/**/*.e2e.ts"],
framework: "mocha",
services: [
["tauri", {
appBinaryPath: "./src-tauri/target/release/tauri-app",
driverProvider: "embedded",
}],
],
};
// e2e/greet.e2e.ts
describe("인사 화면", () => {
it("이름을 넣으면 인사말을 보여 준다", async () => {
await $("#greet-input").setValue("Tauri");
await $("button[type='submit']").click();
await expect($("#greet-msg")).toHaveText(/Tauri/);
});
});
전통적인 방법은 tauri-driver입니다. cargo install tauri-driver --locked로 설치하면 운영체제의 네이티브 WebDriver를 감싸 줍니다. Windows에서는 설치된 Edge와 버전이 맞는 msedgedriver.exe가 PATH에 있어야 하고(버전이 다르면 연결 단계에서 멈출 수 있습니다), Linux에서는 WebKitWebDriver(Debian 계열 패키지 webkit2gtk-driver)가 필요합니다. macOS에는 WKWebView용 WebDriver 도구가 없어 이 방법을 쓸 수 없습니다. Node.js를 쓰지 않는다면 Selenium 같은 다른 WebDriver 클라이언트와 함께 쓸 수 있습니다.
CI의 Linux 환경에는 화면이 없으므로 xvfb-run 같은 가상 디스플레이 아래에서 E2E 테스트를 실행합니다.
정리
- 로직은 순수 함수로 떼어
cargo test로 시험하고, 명령은 얇게 유지합니다. - 프런트엔드는
mockIPC로 Rust 응답을 흉내 내 Vitest 등으로 시험하고, 테스트마다 clearMocks로 정리합니다. - E2E는 WebDriver로 빌드된 앱을 조작합니다. WebdriverIO의 Tauri 서비스가 권장되며,
tauri-driver는 Windows와 Linux만 지원합니다.
댓글 0개
로그인 · 로그인하면 댓글을 남길 수 있습니다.