0Pricing
Testing Mastery: JUnit, Mockito & Integration Tests · 강의

실제 객체 감시하기

Mockito 스파이를 사용해 실제 메서드를 호출하면서도 상호 작용을 검증하도록 실제 객체의 일부만 목으로 만드는 방법을 알아봅니다.

실제 객체 감시하기은(는) CoddyKit의 무료 Testing Mastery: JUnit, Mockito & Integration Tests 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Testing Mastery: JUnit, Mockito & Integration Tests 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Testing Mastery: JUnit, Mockito & Integration Tests 강의에는 총 4개의 강의가 포함되어 있습니다.

이 강의의 일부는 아직 번역되지 않았으며 영어로 표시됩니다.

What are Mockito Spies?

In Mockito, you've learned to create mocks to fully control object behavior. But what if you only want to change a few methods while keeping the original behavior for others?

That's where spies come in! A spy wraps a real object, allowing you to:

  • Call the object's actual methods by default.
  • Override (stub) specific methods to return predefined values.
  • Verify interactions with the real object.

Think of it as 'partial mocking' – using the real thing, but with a few tweaks.

Creating Your First Spy

Creating a spy is straightforward. Instead of Mockito.mock(), you use Mockito.spy() and pass in an instance of the real object you want to spy on.

Let's define a simple DataService class we'll use for our examples. This service will perform some operations.

import org.mockito.Mockito;

public class DataService {
    public String fetchData(String id) {
        return "Real data for " + id;
    }

    public int processData(String data) {
        return data.length();
    }
}

public class Main {
    public static void main(String[] args) {
        DataService realService = new DataService();
        DataService spyService = Mockito.spy(realService);

        System.out.println("Spy created successfully!");
    }
}

Spies Call Real Methods

The key characteristic of a spy is that, by default, it will call the actual methods of the object it's wrapping. This is different from a mock, which has no real implementation and returns default values.

Let's see our spyService call a real method:

import org.mockito.Mockito;

public class DataService {
    public String fetchData(String id) {
        System.out.println("--- Calling REAL fetchData for ID: " + id + " ---");
        return "Real data for " + id;
    }

    public int processData(String data) {
        return data.length();
    }
}

public class Main {
    public static void main(String[] args) {
        DataService realService = new DataService();
        DataService spyService = Mockito.spy(realService);

        String result = spyService.fetchData("123");
        System.out.println("Result from spy: " + result);

        int processed = spyService.processData("Hello");
        System.out.println("Processed data length: " + processed);
    }
}

Stubbing a Spy: Overriding Behavior

While spies call real methods by default, you can still stub them to return specific values or throw exceptions, just like with mocks. This lets you control parts of the object's behavior.

However, when stubbing a spy, it's often safer to use doReturn().when() syntax:

  • Mockito.when(spy.method()).thenReturn(value) might execute the real method first if it's called during the when() part.
  • Mockito.doReturn(value).when(spy).method() avoids calling the real method during stubbing, which is crucial if the real method has side effects or throws exceptions.

Stubbing a Spy in Action

Let's stub our spyService's fetchData method to return a custom value for a specific ID, while other calls still go to the real method:

import org.mockito.Mockito;

public class DataService {
    public String fetchData(String id) {
        System.out.println("--- Calling REAL fetchData for ID: " + id + " ---");
        return "Real data for " + id;
    }

    public int processData(String data) {
        return data.length();
    }
}

public class Main {
    public static void main(String[] args) {
        DataService realService = new DataService();
        DataService spyService = Mockito.spy(realService);

        // Stubbing the spy for a specific input
        Mockito.doReturn("Mocked data for specific ID")
               .when(spyService)
               .fetchData("specialId");

        // This call will return the mocked data
        String result1 = spyService.fetchData("specialId");
        System.out.println("Result for specialId: " + result1);

        // This call will go to the real method
        String result2 = spyService.fetchData("regularId");
        System.out.println("Result for regularId: " + result2);
    }
}

Verifying Spy Interactions

Just like with mocks, you can use Mockito.verify() to ensure that certain methods were called on your spy. This is powerful for confirming that your code interacts with the real object as expected.

verify() works exactly the same for spies as it does for mocks. You can check:

  • If a method was called.
  • How many times it was called.
  • With what arguments it was called.

Verifying Spy Calls Example

Let's verify that our fetchData method was called on the spy, even when it executed its real implementation:

import org.mockito.Mockito;

public class DataService {
    public String fetchData(String id) {
        System.out.println("--- Calling REAL fetchData for ID: " + id + " ---");
        return "Real data for " + id;
    }

    public int processData(String data) {
        return data.length();
    }
}

public class Main {
    public static void main(String[] args) {
        DataService realService = new DataService();
        DataService spyService = Mockito.spy(realService);

        // Call a method on the spy (it will execute the real method)
        spyService.fetchData("user1");
        spyService.processData("data1");
        spyService.fetchData("user2");

        // Verify interactions
        Mockito.verify(spyService).fetchData("user1");
        Mockito.verify(spyService, Mockito.times(2)).fetchData(Mockito.anyString());
        Mockito.verify(spyService).processData("data1");

        System.out.println("Verification successful!");
    }
}

Spies vs. Mocks: The Key Difference

It's crucial to understand when to use a spy versus a traditional mock:

  • Mocks: Create a completely fake object. All methods are 'empty' and return default values unless you explicitly stub them. Ideal for isolating the unit under test.
  • Spies: Wrap a real object. All methods execute their actual implementation unless you explicitly stub them. Useful when you want to use most of the real object's behavior but control a few specific interactions.

Prefer mocks for true unit isolation. Use spies when dealing with complex objects where only a few methods need to be controlled, or for legacy code.

When to Use Spies

Spies are particularly useful in scenarios where:

  • You're testing a class that interacts with a complex dependency, and you only need to override a small part of that dependency's behavior.
  • You have a legacy class with many methods, and creating a full mock would be tedious, but you need to ensure some methods are called or return specific values.
  • You want to test partial behavior of a real object without fully replacing it.

However, use them sparingly. Over-reliance on spies can lead to less isolated tests that are harder to maintain.

Quick Check: Spy Behavior

Consider a Logger class with a log(String message) method that prints to console. If you spy on a new Logger() object, what happens when you call spyLogger.log("Test") without any stubbing?

Recap: Spying on Real Objects

You've successfully learned about Mockito spies!

  • Spies wrap real objects, allowing you to use their actual methods by default.
  • You create them with Mockito.spy(realObject).
  • You can stub specific methods using doReturn().when(spy).method() to override their behavior.
  • You can verify interactions on spies using Mockito.verify(), just like with mocks.
  • Use spies carefully, primarily when partial control over a real object is needed, rather than full isolation.

This flexibility helps you write more targeted tests for complex scenarios.

자주 묻는 질문

“실제 객체 감시하기” 강의는 무료인가요?

네 — “실제 객체 감시하기” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Testing Mastery: JUnit, Mockito & Integration Tests 강의 전체를 잠금 해제할 수 있습니다. Testing Mastery: JUnit, Mockito & Integration Tests 강의에는 총 4개의 강의가 포함되어 있습니다.

“실제 객체 감시하기”에서 뭘 배우나요?

Mockito 스파이를 사용해 실제 메서드를 호출하면서도 상호 작용을 검증하도록 실제 객체의 일부만 목으로 만드는 방법을 알아봅니다. 브라우저에서 직접 실행하는 실습 코드로 Testing Mastery: JUnit, Mockito & Integration Tests을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Testing Mastery: JUnit, Mockito & Integration Tests을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Testing Mastery: JUnit, Mockito & Integration Tests은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.

“실제 객체 감시하기” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Testing Mastery: JUnit, Mockito & Integration Tests 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Testing Mastery: JUnit, Mockito & Integration Tests 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 반환 값 스터빙
  2. Mockito 인수 매처
  3. 실제 객체 감시하기
  4. 예외 발생과 연속 호출
← Testing Mastery: JUnit, Mockito & Integration Tests(으)로 돌아가기