--maxWorkers='50%'import { useEffect, useState } from "react"import { View } from "react-native"import { Text } from "./Text"export function DelayedContent() { const [showContent, setShowContent] = useState(false) useEffect(() => { const timer = setTimeout(() => { setShowContent(true) }, 4000) return () => clearTimeout(timer) }, []) return ( <View> <Text>Loading...</Text> {showContent && <Text>Content loaded!</Text>} </View> )}import { render } from "@testing-library/react-native"import { DelayedContent } from "./DelayedContent"import { ThemeProvider } from "../theme/context"describe("DelayedContent", () => { it("should show content after delay", async () => { const { findByText } = render( <ThemeProvider> <DelayedContent /> </ThemeProvider>, ) const content = await findByText("Content loaded!", {}, { timeout: 5000 }) expect(content).toBeDefined() })})DelayedContent는 4초 후에 Content Loaded! 문자열을 보여줍니다. 하지만 JavaScript에서 setTimeout은 함수를 실행하기 전의 최소 시간을 설정할 뿐, 실행 시간을 보장하지 않습니다. 따라서 JavaScript 프로세스가 느려지고 setTimeout이 테스트 단언문의 타임아웃보다 오래 걸리면, 테스트는 다음과 같이 실패하게 됩니다.FAIL app/components/DelayedContent.test.tsx (31.954 s, 87 MB heap size) DelayedContent ✕ should show content after delay (5059 ms) ● DelayedContent › should show content after delay thrown: "Exceeded timeout of 5000 ms for a test. Add a timeout value to this test to increase the timeout, if this is a long-running test. See https://jestjs.io/docs/api#testname-fn-timeout."--maxWorkers 플래그가 여기서 도움이 됩니다. --maxWorkers='50%'로 설정하면 Jest가 시스템의 CPU 코어 수의 절반만 워커로 사용하도록 강제합니다.DelayedContent 컴포넌트를 추가했습니다.import { useEffect, useState } from "react"import { View } from "react-native"import { Text } from "./Text"export function DelayedContent() { const [showContent, setShowContent] = useState(false) useEffect(() => { const timer = setTimeout(() => { setShowContent(true) }, 4000) return () => clearTimeout(timer) }, []) return ( <View> <Text>Loading...</Text> {showContent && <Text>Content loaded!</Text>} </View> )}import { render } from "@testing-library/react-native"import { DelayedContent } from "./DelayedContent"import { ThemeProvider } from "../theme/context"describe("DelayedContent", () => { it("should show content after delay", async () => { const { findByText } = render( <ThemeProvider> <DelayedContent /> </ThemeProvider>, ) const content = await findByText("Content loaded!", {}, { timeout: 5000 }) expect(content).toBeDefined() })})Dockerfile을 만들고, 다양한 조건에서 Jest 스위트를 실행하고 시스템 메모리 동작을 검사하는 스크립트를 가져왔습니다. 이 글의 나머지 부분에서는 Jest가 시스템 메모리 사용량에 어떤 영향을 미치는지, 그리고 그것이 테스트 안정성에 무엇을 의미하는지에 대한 세부적인 실험 과정과 결과를 안내해 드리겠습니다.yarnyarn docker:buildnode:24-alpine 이미지를 내려받고, 작업 디렉토리를 컨테이너로 복사한 후, 테스트를 실행하고 백그라운드에서 메모리 사용량을 모니터링하는 명령을 설정합니다.yarn docker:testyarn test이며, 타이밍 정보를 비교하고 테스트 파일의 메모리 사용량을 확인하기 위해 --verbose와 --logHeapUsage 플래그를 사용합니다.scripts/monitor-memory.sh 스크립트를 시작합니다. 이 스크립트는 cgroup의 memory.stat 파일에서 메모리 사용량 통계를 폴링합니다. 이 파일은 cgroup의 메모리 풋프린트를 다양한 통계로 세분화하여 보여줍니다.scripts/monitor-memory.sh 스크립트는 다음 정보를 폴링합니다.
MEMORY_LIMIT_MB 플래그를 사용하여 제어 그룹에 메모리 제한을 적용할 수 있습니다. 이전 실행에서 확인한 테스트 파일들의 메모리 사용량 중간 정도인 200MB로 제한을 설정하는 편리한 스크립트가 있습니다. Jest는 가능한 한 많은 워커를 실행하려 할 것이고, cgroup은 해당 워커들을 위한 가용 메모리가 빠르게 부족해질 것입니다. memory.stat에서 테스트 속도가 느려지고 메모리 압박 징후가 늘어나는 것을 볼 수 있을 것입니다.yarn docker:test:constrained
DelayedContent 컴포넌트 테스트에서 타임아웃 오류가 발생한 것을 확인할 수 있습니다. 또한 memory.stat을 통해 메모리 압박의 증거도 확보했습니다. 이는 우리의 원래 가설을 뒷받침합니다. Jest 성능은 메모리가 제한된 환경에서 저하되며, 일부 테스트에서 타임아웃 오류를 일으킬 수 있습니다.--maxWorkers가 상황을 어떻게 바꾸는지 관찰해 봅시다. 동일한 200MB 메모리 제한 환경에서 --maxWorkers=2로 실행하는 스크립트를 사용합니다.yarn docker:test:constrained:workers
maxWorkers나 메모리 제한을 조정해 보면 이러한 변수들이 결과와 어떻게 상호작용하는지 금방 감을 잡으실 수 있을 것입니다. 전반적으로 maxWorkers는 메모리 압박 문제를 방지하는 데 효과적일 수 있지만, 이는 균형의 문제입니다. 적절한 값은 가용 시스템 리소스와 테스트 스위트의 메모리 소비량에 따라 달라집니다.yarn docker:test:constrained:noswapmemory.max를 memory.high로 변경합니다. 이는 제한에 도달했을 때 OOM으로 프로세스를 죽이는 대신 메모리 사용을 억제(Throttle)합니다.0 바이트로 설정하여 cgroup이 스왑 메모리를 절대 사용하지 못하게 합니다.
--maxWorkers로 해결할 수 있습니다. 저장소의 편리한 스크립트를 사용하여 --maxWorkers=2로 동일한 명령을 실행해 봅니다.yarn docker:test:constrained:noswap:workers
시나리오 | 시간 | 메이저 페이지 폴트 | 페이지 스캔 | 결과 |
|---|---|---|---|---|
제한 없음 | 7s | 0 | 0 | ✅ 통과 |
200MB 제한 | 19s | 642,166 | 3,025,671 | ❌ 타임아웃 |
200MB + maxWorkers=2 | 9s | 72,219 | 674,557 | ✅ 통과 |
800MB 소프트 제한, 스왑 없음 | 51s | 2 | 16,740,650 | ❌ 타임아웃 |
800MB 소프트 제한, 스왑 없음 + maxWorkers=2 | 7s | 1 | 0 | ✅ 통과 |
maxWorkers 수를 설정하여 이를 해결할 수 있습니다.maxWorkers를 미세 조정하거나, 두 방법 사이의 균형을 찾아야 합니다. 저는 이 플래그를 --maxWorkers='50%'로 설정하여 성공적인 결과를 얻었지만, 여러분에게 가장 적합한 설정은 직접 실험을 통해 찾아야 할 것입니다. 이 글이 여러분만의 구체적인 조사를 진행하는 데 도움이 되는 도구가 되었기를 바랍니다.아직 댓글이 없습니다.
첫 번째 댓글을 작성해보세요!