유니티 DataTableManager을 만들고, 데이터가 제대로 로드되는지 확인하기 위한 테스트 데이터와 테스트 코드가 필요했다. 그래서 커서를 사용해서 테스트 코드를 만들어본 후기를 작성해본다.
1. 커서로 사용한 이유
2. 테스트 과정
3. 후기
1. 커서로 사용한 이유
일단 전에 VSCode, VS를 이용하다가 현재는 cursor을 이용하게 되었다. 그 이유는 유니티 상에서 자연어 프롬프트를 이용한 AI와의 페어 프로그래밍을 경험해보고 싶었고, 통합된 개발 환경(IDE)에 AI가 내장된 형태여서 코드 작성, 구조 분석, 디버깅, 리팩토링까지 전체적인 작업이 지원 가능하기 때문이다.
2. 테스트 과정
테스트 과정은 다음과 같다.
우선 예전에 프로젝트 내에 ..파일을 만들라고 했는데 위치 설정을 넣어주지 않아서 코드가 다른 프로젝트에 생성되었다.
일단 러프하게 원하는 코드 기능이 잘 작동하는지 테스트하려고 했다.
DataTableManager, @Assets/Scripts/Utility/CSVReader.cs 기능이 잘 작동하는지 테스트해
이렇게 하니 cursor가 현재 프로젝트 내에서 관련 파일을 찾고, 프로젝트 구조를


갑자기 버그를 찾고 버그를 수정하고 있어서 다급하게 멈췄다.
그리고 프롬프트를 다음과 같이 수정했다.
DataTableManager, @Assets/Scripts/Utility/CSVReader.cs 기능이 잘 작동하는지 테스트해.
테스트를 위해 수정할 부분은 수정했다고 표시하고, 다른 이유로 수정할 코드는 내가 리뷰 먼저 한 후 수정을
내가 결정하도록 설정해. 만약 이 때 수정하기로 결정하면 수정했다고 표시해..
테스트 후에 테스트를 위해 수정한 부분은 주석처리해.
코드를 수정하려고 해서 수정 전에 리뷰를 요청하도록 추가하고, 테스트를 위해 추가되는 임의의 코드들이 있어서 해당 코드들에 대해 테스트 후 주석표시하라고 설정했다. (작성한 코드 중 필요한 내용이 있을지도 모르므로)

테스트를 위해 private를 임의로 public으로 바꿨다.
그리고 테스트를 위해 임의로 CSVReaderAndDataTableTest.cs를 만들었다.
using UnityEngine;
using System.Collections.Generic;
using BalancingLibra.Data;
// CSVReader와 DataTableManager 기능 테스트
public class CSVReaderAndDataTableTest : MonoBehaviour
{
private void Start()
{
Debug.Log("=== CSVReader 및 DataTableManager 테스트 시작 ===");
TestCSVReader();
TestDataTableManager();
Debug.Log("=== 모든 테스트 완료 ===");
}
// CSVReader 기능 테스트
private void TestCSVReader()
{
Debug.Log("\n--- CSVReader 테스트 시작 ---");
// 테스트 1: ParseLine - 기본 CSV 라인 파싱
string testLine1 = "id,name,value";
string[] result1 = CSVReader.ParseLine(testLine1);
Debug.Log($"[Test 1] ParseLine 테스트");
Debug.Log($" 입력: {testLine1}");
Debug.Log($" 결과: [{string.Join(", ", result1)}]");
Debug.Log($" 성공: {result1.Length == 3 && result1[0] == "id" && result1[1] == "name" && result1[2] == "value"}");
// 테스트 2: ParseLine - 빈 값 포함
string testLine2 = "1,Item A,100";
string[] result2 = CSVReader.ParseLine(testLine2);
Debug.Log($"[Test 2] ParseLine - 숫자 포함 테스트");
Debug.Log($" 입력: {testLine2}");
Debug.Log($" 결과: [{string.Join(", ", result2)}]");
Debug.Log($" 성공: {result2.Length == 3 && result2[0] == "1" && result2[1] == "Item A" && result2[2] == "100"}");
// 테스트 3: ParseCSV - 헤더 제외 파싱
string testCSV1 = "id,name,value\n1,Item A,100\n2,Item B,200\n3,Item C,300";
List<string[]> result3 = CSVReader.ParseCSV(testCSV1);
Debug.Log($"[Test 3] ParseCSV - 기본 테스트");
Debug.Log($" 입력 CSV:\n{testCSV1}");
Debug.Log($" 파싱된 행 수: {result3.Count} (헤더 제외)");
Debug.Log($" 첫 번째 행: [{string.Join(", ", result3[0])}]");
Debug.Log($" 성공: {result3.Count == 3 && result3[0][0] == "1" && result3[1][1] == "Item B"}");
// 테스트 4: ParseCSV - 빈 줄 처리
string testCSV2 = "id,name,value\n1,Item A,100\n\n2,Item B,200\n";
List<string[]> result4 = CSVReader.ParseCSV(testCSV2);
Debug.Log($"[Test 4] ParseCSV - 빈 줄 처리 테스트");
Debug.Log($" 입력 CSV:\n{testCSV2}");
Debug.Log($" 파싱된 행 수: {result4.Count} (빈 줄 제외)");
Debug.Log($" 성공: {result4.Count == 2}");
// 테스트 5: ParseCSV - 헤더만 있는 경우
string testCSV3 = "id,name,value";
List<string[]> result5 = CSVReader.ParseCSV(testCSV3);
Debug.Log($"[Test 5] ParseCSV - 헤더만 있는 경우");
Debug.Log($" 입력 CSV: {testCSV3}");
Debug.Log($" 파싱된 행 수: {result5.Count}");
Debug.Log($" 성공: {result5.Count == 0}");
// 테스트 6: ParseCSV - 빈 CSV
string testCSV4 = "";
List<string[]> result6 = CSVReader.ParseCSV(testCSV4);
Debug.Log($"[Test 6] ParseCSV - 빈 CSV 테스트");
Debug.Log($" 입력 CSV: (빈 문자열)");
Debug.Log($" 파싱된 행 수: {result6.Count}");
Debug.Log($" 성공: {result6.Count == 0}");
Debug.Log("--- CSVReader 테스트 완료 ---\n");
}
// DataTableManager 기능 테스트
private void TestDataTableManager()
{
Debug.Log("--- DataTableManager 테스트 시작 ---");
// 테스트용 Mock 테이블 클래스 생성
TestDataTable testTable = new TestDataTable();
// 테스트 1: IDataTable.Load 메서드 테스트
Debug.Log("[Test 1] IDataTable.Load 메서드 테스트");
testTable.Load("Test/Path");
Debug.Log($" Load 호출 후 데이터: {testTable.Data}");
bool test1Success = testTable.Data == "Test/Path";
Debug.Log($" 성공: {test1Success}");
// 테스트 2: DataTableManager 인스턴스 확인
Debug.Log("[Test 2] DataTableManager 인스턴스 확인");
DataTableManager manager = DataTableManager.Instance;
bool test2Success = manager != null;
Debug.Log($" 인스턴스 존재: {manager != null}");
Debug.Log($" 성공: {test2Success}");
if (!test2Success)
{
Debug.LogError(" DataTableManager 인스턴스를 가져올 수 없습니다. 테스트를 중단합니다.");
return;
}
// 테스트 3: LoadTable 메서드 - 테이블 로드 및 등록
Debug.Log("[Test 3] LoadTable 메서드 - 테이블 로드 및 등록");
// manager.LoadTable<TestDataTable>("Test/Data/Path"); // LoadTable이 private이므로 주석처리
TestDataTable loadedTable = manager.Get<TestDataTable>();
bool test3Success = loadedTable != null && loadedTable.Data == "Test/Data/Path";
Debug.Log($" 로드된 테이블 존재: {loadedTable != null}");
if (loadedTable != null)
{
Debug.Log($" 로드된 테이블 데이터: {loadedTable.Data}");
}
Debug.Log($" 성공: {test3Success}");
// 테스트 4: LoadTable 메서드 - 중복 로드 시 업데이트 확인
Debug.Log("[Test 4] LoadTable 메서드 - 중복 로드 시 업데이트 확인");
// manager.LoadTable<TestDataTable>("Test/Updated/Path"); // LoadTable이 private이므로 주석처리
TestDataTable updatedTable = manager.Get<TestDataTable>();
bool test4Success = updatedTable != null && updatedTable.Data == "Test/Updated/Path";
Debug.Log($" 업데이트된 테이블 데이터: {(updatedTable != null ? updatedTable.Data : "null")}");
Debug.Log($" 이전 테이블 데이터: {loadedTable.Data}");
Debug.Log($" 성공: {test4Success}");
// 테스트 5: Get 메서드 - 존재하지 않는 테이블
Debug.Log("[Test 5] Get 메서드 - 존재하지 않는 테이블");
TestDataTable2 nonExistentTable = manager.Get<TestDataTable2>();
bool test5Success = nonExistentTable == null;
Debug.Log($" 결과: {nonExistentTable}");
Debug.Log($" 성공: {test5Success}");
Debug.Log("--- DataTableManager 테스트 완료 ---\n");
}
// 테스트용 Mock IDataTable 구현 2 (존재하지 않는 테이블 테스트용)
private class TestDataTable2 : IDataTable
{
public string Data { get; private set; } = "";
public void Load(string path)
{
Data = path;
Debug.Log($"[TestDataTable2] Load 호출됨: {path}");
}
}
// 테스트용 Mock IDataTable 구현
private class TestDataTable : IDataTable
{
public string Data { get; private set; } = "";
public void Load(string path)
{
Data = path;
Debug.Log($"[TestDataTable] Load 호출됨: {path}");
}
}
}


이와 같이 테스트 실행 방법과 결과, 테스트할 내용들을 친절하게 알려준다.
그리고 나는 이 테스트 결과를 보면서 알았다. 나는 임의의 csv 파일을 만든 후, 해당 파일을 불러왔을 때(실제로 데이터를 불러올 때) 테스트가 잘 되는지 확인하고 싶었던 것이다.
그래서 아래와 같이 프롬프트를 다시 작성했다.
첫 기능 단위 테스트는 성공적이야. 그리고 다음으로 아래 2가지 기능을 테스트해.
1. Resources/Data에 ItemTable.csv를 임의로 만들고, 게임 실행 시 콘솔에
[ItemTable] 아이템 n개가 로드되게 한 후 아이템 로드 완료되었다고 로그를 출력 후 확인해
2. csv에 입력된 id, name, description이 인게임 객체에 전확히 매핑되는지 테스트해
지금은 테스트를 원하는 내용을 명확하게 작성했다.
그리고 Resources/Data ItemTable.csv를 생성하고, DataTableManager에서 ItemTable을 로드하도록 수정했다. 그리고 ItemTable에 로그를 추가했다.

내가 제작한 Logger 클래스의 로그를 사용하고 있다.
그리고 생성/수정된 파일들에 대한 설명을 진행한 후 테스트 실행 방법과 예상 콘솔 출력 내역, 테스트 항목 등을 소개했다.
테스트 방법대로 씬에 빈 GameObject를 생성하고, ItemTableTest컴포넌트를 추가한 후 Play모드를 실행하니 내가 생각한 테스트 항목이 성공적으로 작성되었다.
그리고 DataTableManager.cs, CSVReader.cs에서 수정된 내역들을 다시 원래대로 돌려놓으려고 했다.
@Assets/Scripts/DataTableManager.cs , @Assets/Scripts/Utility/CSVReader.cs 에
포함된 테스트용 코드들을 다시 원래대로 돌려놔.
다른 조건들은 내버려둬
이렇게 하니 수정 사항을 다시 알려주고, 다시 원래대로 돌려놨다.
3. 후기
역시 AI를 쓸 때는 내가 내 코드를 완벽하게 이해하고 작업하는 것이 중요하다는 것을 느꼈다. 작동하다가 버그도 고쳐버리기까지 하니 말이다.
그리고 내가 무엇을 원하는지 명확하게 먼저 명세서를 작성한 뒤에 작업하는 것이 효율이 가장 뛰어난 느낌이다. 테스트를 본격적으로 한 지 얼마 되지 않아서 어떤 것을 원하는지 알기가 어려웠다는 점도 맹점이다.
커서를 사용해 명령할 때는 내가 어떤 것을 원하는지 정확히 명세를 해 놓은 뒤에 사용해야겠다. AI보다 내가 뭘 원하는지 명확하게 표현하는 것이 더 어렵다고 느꼈다.