test 가능한 renderer abstraction 만들기
GPU output은 테스트하기 어렵습니다. 그래서 editor core와 renderer contract를 분리해, 픽셀 비교 없이도 많은 것을 검증할 수 있게 만듭니다.
draw command log로 renderer를 테스트하는 코드
GPU 픽셀을 바로 비교하기 전에, renderer가 올바른 draw command를 만들었는지 테스트합니다.
class RecordingRenderer {
commands = [];
drawRect(node, pipeline) {
this.commands.push({
type: "drawRect",
nodeId: node.id,
pipeline,
bounds: node.bounds
});
}
clear() {
this.commands.push({ type: "clear" });
}
}
test("selected rectangle is drawn before overlay", () => {
const renderer = new RecordingRenderer();
renderScene(snapshot, renderer);
expect(renderer.commands.map((cmd) => cmd.type)).toEqual([
"clear",
"drawRect",
"drawSelectionOverlay"
]);
});
테스트할 경계
core command test
scene projection snapshot
renderer draw command log
small pixel sample
픽셀 테스트는 핵심 렌더링 경로에 제한적으로 사용하고 tolerance를 명시합니다.
draw command snapshot을 안정적으로 만든다
function normalizeDrawCommands(commands) {
return commands.map((command) => ({
...command,
bounds: command.bounds && {
x: Math.round(command.bounds.x),
y: Math.round(command.bounds.y),
width: Math.round(command.bounds.width),
height: Math.round(command.bounds.height)
}
}));
}
expect(normalizeDrawCommands(renderer.commands)).toMatchInlineSnapshot();
floating point 값이 그대로 snapshot에 들어가면 테스트가 자주 깨집니다. renderer contract 테스트에서는 의미 있는 단위로 반올림하고, 픽셀 테스트는 더 작은 핵심 장면에만 사용합니다.
오늘의 핵심
테스트 가능한 renderer는 우연히 만들어지지 않습니다. core와 backend를 분리한 이유가 여기서 드러납니다.