Java - Serializable 테스트

꾸준히·2025년 8월 2일

Java

목록 보기
2/2
post-thumbnail

Java Serializable 테스트로 알아보는 직렬화의 핵심

테스트 코드를 통해 Java의 Serializable 인터페이스가 어떻게 동작하는지 직접 확인해보겠습니다.

📋 목차

  1. 테스트 개요
  2. 성공 케이스: 정상적인 직렬화/역직렬화
  3. 실패 케이스 1: Serializable 미구현
  4. 실패 케이스 2: 직렬화 불가능한 필드
  5. 실패 케이스 3: serialVersionUID 불일치
  6. 핵심 정리

테스트 개요

Java의 직렬화(Serialization)는 객체를 바이트 스트림으로 변환하여 파일이나 네트워크로 전송할 수 있게 해주는 기능입니다. 이 기능이 어떻게 동작하고 언제 실패하는지 실제 테스트 코드를 통해 알아보겠습니다.

테스트 환경:

  • JUnit 5 (Jupiter)
  • AssertJ
  • Java 17

1. 성공 케이스: 정상적인 직렬화/역직렬화

먼저 Serializable을 올바르게 구현한 클래스가 정상적으로 직렬화/역직렬화되는지 확인해보겠습니다.

@Test
void serializableClassShouldBeSerializedAndDeserialized() throws Exception {
  // Given: Serializable을 구현한 객체 생성
  SerializablePerson person = new SerializablePerson("홍길동", 20);
  
  // When: 객체를 직렬화
  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  ObjectOutputStream oos = new ObjectOutputStream(baos);
  oos.writeObject(person);
  oos.close();

  // And: 직렬화된 데이터를 다시 역직렬화
  ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
  SerializablePerson result = (SerializablePerson) ois.readObject();
  ois.close();

  // Then: 원본 데이터가 정확히 복원되어야 함
  assertThat(result.name).isEqualTo("홍길동");
  assertThat(result.age).isEqualTo(20);
}

✅ 결과: Serializable을 구현한 객체는 정상적으로 직렬화/역직렬화되며, 모든 필드 값이 정확히 복원됩니다.

2. 실패 케이스 1: Serializable 미구현

Serializable 인터페이스를 구현하지 않은 클래스를 직렬화하면 어떻게 될까요?

@Test
void nonSerializableClassShouldThrowException() {
  // Given: Serializable을 구현하지 않은 객체
  NonSerializablePerson person = new NonSerializablePerson("임꺽정", 30);
  
  // When & Then: 직렬화 시도 시 NotSerializableException 발생
  assertThatThrownBy(() -> {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(baos);
    oos.writeObject(person); // 여기서 예외 발생!
  }).isInstanceOf(NotSerializableException.class);
}

❌ 결과: NotSerializableException이 발생하며 직렬화에 실패합니다. Java는 안전성을 위해 명시적으로 Serializable을 구현한 클래스만 직렬화를 허용합니다.

3. 실패 케이스 2: 직렬화 불가능한 필드

Serializable을 구현했더라도, 직렬화할 수 없는 필드가 포함되어 있으면 어떻게 될까요?

@Test
void nonSerializableClassWithNonSerializableFieldsShouldThrowException() {
  // Given: Serializable을 구현했지만 Thread 필드를 가진 객체
  NonSerializablePerson2 person = new NonSerializablePerson2("이몽룡", 25, Thread.currentThread());
  
  // When & Then: Thread는 직렬화 불가능하므로 예외 발생
  assertThatThrownBy(() -> {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(baos);
    oos.writeObject(person); // Thread 필드 때문에 실패
  }).isInstanceOf(NotSerializableException.class);
}

❌ 결과: Thread, Socket, InputStream 등은 직렬화할 수 없는 객체입니다. 이런 필드가 있으면 전체 객체의 직렬화가 실패합니다.

💡 해결책: transient 키워드를 사용하여 해당 필드를 직렬화에서 제외할 수 있습니다.

4. 실패 케이스 3: serialVersionUID 불일치

serialVersionUID가 다를 때 역직렬화가 어떻게 실패하는지 확인해보겠습니다.

@Test
void serialVersionUIDMismatchShouldThrowException() throws Exception {
  // Given: 원본 객체를 직렬화
  SerializablePerson person = new SerializablePerson("홍길동", 20);
  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  ObjectOutputStream oos = new ObjectOutputStream(baos);
  oos.writeObject(person);
  oos.close();
  byte[] serializedData = baos.toByteArray();

  // When: serialVersionUID가 다른 클래스로 역직렬화 시도
  class ModifiedSerializablePerson implements Serializable {
    private static final long serialVersionUID = 2L; // 다른 UID!
    String name;
    int age;
    ModifiedSerializablePerson(String name, int age) {
      this.name = name;
      this.age = age;
    }
  }

  // Then: InvalidClassException 발생
  ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(serializedData));
  assertThatThrownBy(ois::readObject)
      .isInstanceOf(java.io.InvalidClassException.class);
  ois.close();
}

❌ 결과: InvalidClassException이 발생합니다. serialVersionUID는 클래스의 버전을 식별하는 ID로, 다르면 역직렬화를 거부합니다.

핵심 정리

✅ 직렬화가 성공하는 조건

  1. Serializable 인터페이스 구현 필수
  2. 모든 필드가 직렬화 가능해야 함
  3. serialVersionUID가 일치해야 함 (역직렬화 시)

❌ 직렬화가 실패하는 경우

  1. Serializable 미구현NotSerializableException
  2. 직렬화 불가능한 필드 존재NotSerializableException
  3. serialVersionUID 불일치InvalidClassException

🔧 실무 팁

  • 중요한 클래스는 serialVersionUID를 명시적으로 선언하세요
  • 직렬화하고 싶지 않은 필드는 transient 키워드 사용
  • 보안이 중요한 데이터(비밀번호 등)는 직렬화에서 제외하세요
profile
타닥..타닥

0개의 댓글