使用OSGi Mocks测试声明式服务注解类遇SCR元数据缺失问题
Let's break down why you're hitting this error and how to fix it, even though you're using a compatible OSGi Mocks version.
First, let's note the odd detail in your error: it says No OSGi SCR metadata found for class com.example.PostServiceTest—your test class, not the PostService you're trying to register. That's a key clue something's off with either your test setup or build configuration.
Here are the steps to resolve this:
1. Verify Your PostService Uses Correct DS Annotations
Make sure your service class is properly annotated with DS 1.3+ annotations so the build can generate the required metadata. For example:
import org.osgi.service.component.annotations.Component; @Component(service = PostService.class, immediate = true) public class PostServiceImpl implements PostService { // Your service logic here }
The service attribute is critical—it tells the OSGi framework (and your build tool) what interface this service implements. Without it, the metadata generator might skip creating the necessary files.
2. Ensure Your Gradle Build Generates DS Metadata
The Gradle AEM Multi project relies on Bnd to generate OSGi metadata. You need to explicitly enable processing of DS annotations in your build configuration:
- Add this to your project's
build.gradle(under theaem.bundleblock):aem { bundle { bnd("-dsannotations: *") } } - Or create a
bnd.bndfile in your bundle module with:-dsannotations: *
This tells Bnd to scan for DS annotations and generate the required OSGI-INF metadata files during compilation.
3. Fix the Test Context Initialization
The error pointing to your test class suggests the mock framework might be incorrectly trying to process it as an OSGi component. Try adjusting how you register the service:
Instead of relying on automatic metadata detection, explicitly specify the service interface when registering:
import java.util.Collections; import org.junit.Rule; import com.day.cq.commons.jcr.JcrConstants; import io.wcm.testing.mock.aem.junit.AemContext; import io.wcm.testing.mock.aem.junit.AemContextCallback; public class PostServiceTest { @Rule public AemContext context = new AemContext((AemContextCallback) context -> { // Explicitly pass the service interface to avoid metadata dependency context.registerInjectActivateService(new PostServiceImpl(), Collections.emptyMap(), PostService.class); }, ResourceResolverType.RESOURCERESOLVER_MOCK); @Test public void shouldFetchRandomPosts() { final PostService postsService = context.getService(PostService.class); final List<Post> posts = postsService.randomPosts(100); assertEquals(100, posts.size()); } }
This bypasses the need for SCR metadata to identify the service type.
4. Check for Dependency Conflicts or Incorrect Versions
Double-check that your sling-mock-osgi dependency is indeed 2.0.0 or higher, and there are no older versions being pulled in transitively. In your build.gradle:
testImplementation 'org.apache.sling:sling-mock-osgi:2.1.20' // Use a recent compatible version
Run ./gradlew dependencies to inspect the dependency tree and resolve any conflicts.
5. Clean and Rebuild Your Project
Old compiled files or cached metadata can cause issues. Run:
./gradlew clean build
This clears out old artifacts and regenerates all metadata from scratch.
6. Ensure Your Test Class Has No Unnecessary OSGi Annotations
Double-check that PostServiceTest doesn't have any DS annotations (like @Component) accidentally added—this would cause the mock framework to treat it as an OSGi component and look for metadata that doesn't exist.
内容的提问来源于stack exchange,提问作者toniedzwiedz

