设置返回值
配置模拟对象,使其方法被调用时返回特定值或抛出异常。
设置返回值 是 CoddyKit 上的免费 Testing Mastery: JUnit, Mockito & Integration Tests 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Testing Mastery: JUnit, Mockito & Integration Tests 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Testing Mastery: JUnit, Mockito & Integration Tests 课程共包含 4 节课。
本课时的部分内容尚未翻译,以英文显示。
Intro to Stubbing Mocks
When you create a mock object, it doesn't have any real behavior. Its methods do nothing by default, often returning null, 0, or empty collections.
Stubbing is the process of teaching a mock object how to respond to specific method calls. It's like giving your mock a script to follow!
This allows you to control the exact conditions for your tests, isolating the code you're actually testing.
Making Mocks Return Values
The most common way to stub a mock is using when().thenReturn(). This tells Mockito: "When this specific method is called on the mock, return this predefined value."
when(mock.someMethod()).thenReturn(value);
The value can be any object or primitive type that matches the method's return type.
thenReturn() Code Example
Try running this simple example. Notice how the mock's add method returns our stubbed value only when called with (1, 1).
import static org.mockito.Mockito.*;
interface CalculatorService {
int add(int a, int b);
}
public class Main {
public static void main(String[] args) {
// Create a mock of CalculatorService
CalculatorService mockCalc = mock(CalculatorService.class);
// Stub the add(1, 1) method to return 5
when(mockCalc.add(1, 1)).thenReturn(5);
// Call the stubbed method
System.out.println("1 + 1 = " + mockCalc.add(1, 1));
// Call a method that was NOT stubbed
System.out.println("2 + 2 = " + mockCalc.add(2, 2));
}
}Mocks Throwing Errors
Sometimes you need to test how your code handles errors. You can configure a mock to throw an exception when a specific method is called, using when().thenThrow().
when(mock.failingMethod()).thenThrow(new SomeException("Error!"));
This is crucial for testing error paths and ensuring your application gracefully handles unexpected situations.
thenThrow() Code Demo
In this example, our DataService mock is configured to throw an IllegalArgumentException if we try to fetch data with an "invalid" ID.
import static org.mockito.Mockito.*;
interface DataService {
String fetchData(String id);
}
public class Main {
public static void main(String[] args) {
DataService mockData = mock(DataService.class);
// Stub fetchData("invalid") to throw an exception
when(mockData.fetchData("invalid"))
.thenThrow(new IllegalArgumentException("ID not found!"));
// Call a method that was NOT stubbed (returns null by default)
System.out.println("Fetching 'valid': " + mockData.fetchData("valid"));
// Call the stubbed method that throws an exception
try {
System.out.println("Fetching 'invalid': " + mockData.fetchData("invalid"));
} catch (IllegalArgumentException e) {
System.out.println("Caught error: " + e.getMessage());
}
}
}Dynamic Responses: thenAnswer()
What if you need the mock's response to depend on the arguments passed to it, or to perform some custom logic?
when().thenAnswer() is your solution. It takes an Answer object (often a lambda or anonymous class) which provides more control:
- You get access to the actual method arguments.
- You can perform calculations or complex logic.
- You can return a value or throw an exception dynamically.
thenAnswer() Code Demo
Here, the multiply method on our mock actually performs the multiplication based on the arguments it receives. This is more dynamic than a fixed return value.
import static org.mockito.Mockito.*;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
interface MathService {
int multiply(int a, int b);
}
public class Main {
public static void main(String[] args) {
MathService mockMath = mock(MathService.class);
// Stub multiply for any two integers to perform actual multiplication
when(mockMath.multiply(anyInt(), anyInt())).thenAnswer(
new Answer<Integer>() {
public Integer answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
Integer arg1 = (Integer) args[0];
Integer arg2 = (Integer) args[1];
return arg1 * arg2; // Custom logic based on arguments
}
}
);
System.out.println("3 * 4 = " + mockMath.multiply(3, 4));
System.out.println("5 * 2 = " + mockMath.multiply(5, 2));
System.out.println("7 * 0 = " + mockMath.multiply(7, 0));
}
}Multiple Returns: Chaining
What if you want a mock method to return different values on successive calls?
Mockito allows you to chain stubbing methods. You can provide multiple return values to thenReturn(), or chain multiple thenReturn(), thenThrow(), or thenAnswer() calls.
when(mock.method()).thenReturn(val1, val2, val3);when(mock.method()).thenReturn(val1).thenThrow(ex).thenReturn(val3);
After all specified values or actions are exhausted, the last one will be repeated for subsequent calls.
Chained Stubbing Demo
Observe how our mock Queue returns "Item A", then "Item B", and then throws an exception on subsequent poll() calls.
import static org.mockito.Mockito.*;
import java.util.Queue;
import java.util.LinkedList;
public class Main {
public static void main(String[] args) {
Queue<String> mockQueue = mock(Queue.class);
// Stub poll() to return different values/actions on successive calls
when(mockQueue.poll())
.thenReturn("Item A")
.thenReturn("Item B")
.thenThrow(new IllegalStateException("Queue is empty!"));
System.out.println("Poll 1: " + mockQueue.poll()); // Returns "Item A"
System.out.println("Poll 2: " + mockQueue.poll()); // Returns "Item B"
try {
System.out.println("Poll 3: " + mockQueue.poll()); // Throws exception
} catch (IllegalStateException e) {
System.out.println("Caught error on Poll 3: " + e.getMessage());
}
// Subsequent calls will repeat the last action (throw exception)
try {
System.out.println("Poll 4: " + mockQueue.poll());
} catch (IllegalStateException e) {
System.out.println("Caught error on Poll 4: " + e.getMessage());
}
}
}Check Your Understanding
You are testing a method that processes items from a queue. You need the queue's poll() method to return "Task 1", then "Task 2", and finally null (indicating an empty queue) for subsequent calls. Which Mockito stubbing approach would you use?
Stubbing Return Values: Recap
In this lesson, you learned how to control the behavior of your mock objects by stubbing their method calls. This is fundamental for isolating the unit under test and creating predictable test environments.
when().thenReturn(): To make a mock method return a specific value.when().thenThrow(): To make a mock method throw an exception.when().thenAnswer(): For dynamic responses based on method arguments or custom logic.- Chaining: To define a sequence of different behaviors for successive calls to the same method.
Next, we'll explore Mockito's argument matchers for even more flexible stubbing and verification!
常见问题解答
「设置返回值」课时是免费的吗?
是的 — 「设置返回值」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Testing Mastery: JUnit, Mockito & Integration Tests 课程的其余内容,请升级到 CoddyKit PRO。 Testing Mastery: JUnit, Mockito & Integration Tests 课程共包含 4 节课。
「设置返回值」这节课中我会学到什么?
配置模拟对象,使其方法被调用时返回特定值或抛出异常。 你通过在浏览器中直接运行的动手代码来练习 Testing Mastery: JUnit, Mockito & Integration Tests,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Testing Mastery: JUnit, Mockito & Integration Tests 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Testing Mastery: JUnit, Mockito & Integration Tests 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。
「设置返回值」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Testing Mastery: JUnit, Mockito & Integration Tests 课中编写并运行代码吗?
能。每节 Testing Mastery: JUnit, Mockito & Integration Tests 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。