Middle
What are Mock, Stab, and Spy in the context of software testing?
sobes.tech AI
Answer from AI
- Mock: A fake object that checks whether the tested code interacts with it as expected (calls certain methods with specific arguments and in the correct order). Mocks verify behavior.
- Stub: A fake object that provides predefined responses to method calls. Stubs are used to control the state of dependencies and focus on the tested object, not on interactions with dependencies. Stubs verify state.
- Spy: A partially fake object that wraps a real object. It allows tracking calls to its methods (arguments, number of calls, etc.), while the real method can still be called. Spies are good for verifying that the real object was used and for checking its behavior.
| Type | Main purpose | Checks |
|---|---|---|
| Mock | Interaction verification | Behavior |
| Stub | Providing data | State |
| Spy | Tracking calls to real object | Behavior and state |
// Example of using Mock with Mockito
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import static org.mockito.Mockito.*;
public class ServiceTest {
@Mock
private Dependency dependencyMock;
private Service service;
@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
service = new Service(dependencyMock);
}
@Test
void shouldCallDependencyMethod() {
service.doSomething();
// Verify that dependencyMethod was called once
verify(dependencyMock, times(1)).dependencyMethod();
}
}
class Service {
private final Dependency dependency;
public Service(Dependency dependency) {
this.dependency = dependency;
}
public void doSomething() {
dependency.dependencyMethod();
}
}
class Dependency {
public void dependencyMethod() {
// Real logic
}
public String getData() {
return "real data";
}
}
// Example of using Stub with Mockito
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
public class AnotherServiceTest {
@Mock
private Dependency dependencyStub;
private AnotherService anotherService;
@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
anotherService = new AnotherService(dependencyStub);
}
@Test
void shouldReturnStubbedData() {
// Set predefined response for getData()
when(dependencyStub.getData()).thenReturn("stubbed data");
String result = anotherService.processData();
// Verify that the service returns data from the stub
assertEquals("processed stubbed data", result);
}
}
class AnotherService {
private final Dependency dependency;
public AnotherService(Dependency dependency) {
this.dependency = dependency;
}
public String processData() {
String data = dependency.getData();
return "processed " + data;
}
}
// Example of using Spy with Mockito
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Spy;
import org.mockito.MockitoAnnotations;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class YetAnotherServiceTest {
@Spy
private Dependency dependencySpy = new Dependency(); // Spies wrap real object
private YetAnotherService yetAnotherService;
@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
yetAnotherService = new YetAnotherService(dependencySpy);
}
@Test
void shouldCallRealAndStubPartial() {
// Can call real method
yetAnotherService.callSpyMethod();
// And verify it was called
verify(dependencySpy, times(1)).dependencyMethod();
// Can override behavior for a specific method
when(dependencySpy.getData()).thenReturn("stubbed data for spy");
String result = yetAnotherService.getDataFromSpy();
// Verify that overridden data was returned
assertEquals("stubbed data for spy", result);
// Also verify that getData() was called
verify(dependencySpy, times(1)).getData();
}
}
class YetAnotherService {
private final Dependency dependency;
public YetAnotherService(Dependency dependency) {
this.dependency = dependency;
}
public void callSpyMethod() {
dependency.dependencyMethod();
}
public String getDataFromSpy() {
return dependency.getData();
}
}