Mastering Spock Unit Tests: From Dependencies to Mocking Static Methods
This article walks through setting up Spock for Java/Groovy projects, lists required Maven dependencies, shows how to handle static‑method mocking with PowerMock and Mockito, and provides concrete code examples for mocking @Autowired components, shared objects, and defining mock behavior.
Technical Solution Overview
The solution is built on the company‑recommended Spock testing framework, which runs on Groovy and extends JUnit. Spock 2.0 requires Groovy 1.+ and Java compatibility, while its built‑in Mock and Spy cover most scenarios. For static‑method mocking, PowerMock together with Mockito is introduced.
Required Maven Dependencies
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>1.2-groovy-2.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-spring</artifactId>
<version>1.2-groovy-2.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>1.7.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.7.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.8.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.4.7</version>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.9.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.objenesis</groupId>
<artifactId>objenesis</artifactId>
<version>3.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>2.1</version>
<scope>test</scope>
</dependency>Non‑Static Resources and Import Management
Because several test frameworks contain overlapping method names, the article advises against using import static to avoid ambiguous imports. It also notes that the project’s IDE may auto‑import the wrong class, so developers should verify imports manually.
Mocking Objects with Spock and PowerMock
@Autowired Constructor Injection
Example controller:
@Api(tags = "SLA规则管理模块")
@Slf4j
@RestController
@RequestMapping("/hickwall/v1/static/sla")
public class FunController {
HttpServletRequest request;
ISlaService service;
@Autowired
public FunController(HttpServletRequest request, ISlaService service) {
this.request = request;
this.service = service;
}
}Spock test:
import com.funtester.service.ISlaService
import com.funtester.vo.sla.SlaBean
import spock.lang.Shared
import spock.lang.Specification
import javax.servlet.http.HttpServletRequest
class FunControllerTest extends Specification {
def service = Mock(ISlaService)
@Shared def request = Mock(HttpServletRequest)
def funController = new FunController(request, service)
}@Autowired Field Injection (No Constructor)
Example service implementation:
public class ApiImpl implements IApi {
@Autowired
private ApiRMapper mapper;
}Spock test snippet:
import com.funtester.mapper.ApiRMapper
import com.funtester.vo.ApiR
import spock.lang.Shared
import spock.lang.Specification
ApiRMapper mapper = Mock(ApiRMapper)
def drive = new ApiImpl(mapper: mapper)PowerMock Usage
When a test class is annotated with @RunWith(PowerMockRunner.class), Spock syntax cannot be used directly; PowerMock’s Mock functionality must be employed for static‑method scenarios.
Note: If a bean contains fields annotated with @Autowired, Lombok’s @AllArgsConstructor should be avoided because it can cause startup failures.
Shared Objects and Initialization
Spock’s @Shared annotation allows a single instance to be reused across feature methods. Without it, the object would be recreated for each test.
Demo of shared SlaBean initialization:
@Shared def slaBean = new SlaBean()
def setupSpec() {
request.getHeader("operator") >> "FunTester"
slaBean.name = "测试"
slaBean.quota = 1
slaBean.upstream = "PRO"
slaBean.threshold = 0.1
slaBean.creator = "FunTester"
slaBean.id = 100
}Defining Mock Behavior in Spock
Basic when‑then‑expect structure:
def "AddSla"() {
when:
def sla = FunController.addSla(slaBean)
then:
service.addSla(_) >> { f ->
assert "FunTester" in f.creator
1
}
expect:
sla.code == 0
sla.data == 1
}Additional examples of return values, exceptions, and delegating to other methods are provided using the _ (any) placeholder.
Mockito + PowerMock Behavior Definition
Mockito is used inside setupSpec to stub static or complex methods before Spock tests run:
Mockito.when(newutil.filter(Mockito.any())).thenReturn(true)
Mockito.when(newutil.filter(Mockito.any())).thenReturn(null)
Mockito.when(newutil.filter(Mockito.any())).thenThrow(Exception.class)
PowerMockito.doNothing().when(newutil).filter(Mockito.any(ArrayList.class))Returning a list of custom objects:
Mockito.when(newser.selectAllService()).thenReturn([
new NewInterface() {{
setUrl("/abc");
setNname("test");
setMethod("GET");
}},
new NewInterface() {{
setUrl("/abcd");
setNname("test");
setMethod("POST");
}},
new NewInterface() {{
setUrl("/abce");
setNname("test");
setMethod("GET");
}}
])Conclusion
The article provides a practical, step‑by‑step guide for integrating Spock, PowerMock, and Mockito into a Java/Groovy backend project, covering dependency management, import pitfalls, mocking strategies for both instance and static methods, and shared object initialization. Following these patterns helps achieve high unit‑test coverage while avoiding common compatibility issues.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
