adamcin commented on code in PR #135: URL: https://github.com/apache/sling-site/pull/135#discussion_r1355134428
########## src/main/jbake/content/documentation/development/osgi-mock.md: ########## @@ -231,3 +235,192 @@ More examples: [mockito-junit5-extension]: https://www.javadoc.io/page/org.mockito/mockito-junit-jupiter/latest/org/mockito/junit/jupiter/MockitoExtension.html [caconfig-mock-plugin]: https://github.com/apache/sling-org-apache-sling-testing-caconfig-mock-plugin/blob/master/src/main/java/org/apache/sling/testing/mock/caconfig/ContextPlugins.java [caconfig-mock-plugin-test]: https://github.com/apache/sling-org-apache-sling-testing-caconfig-mock-plugin/blob/master/src/test/java/org/apache/sling/testing/mock/caconfig/ContextPluginsTest.java + +## Config Annotations + +Since osgi-mock 3.4.0, it is possible to use the provided `@UpdateConfig` and `@ApplyConfig` annotations to directly construct component property type ("Config") annotations for use as first-class values in unit tests. Both osgi-mock.junit4 and osgi-mock.junit5 provide different approaches for convenient reflection and injection of these annotations. + +### JUnit 5: OSGi Config Parameters JUnit Extension + +Given an OSGi component class that looks like this: + + #!java + import org.osgi.service.component.annotations.Activate; + import org.osgi.service.component.annotations.Component; + import java.lang.annotation.Retention; + import java.lang.annotation.RetentionPolicy; + + @Component(service = MyService.class) + public class MyService { + + // specify runtime retention to allow for direct usage in unit tests + @Retention(RetentionPolicy.RUNTIME) + public @interface Config { + String path() default "/"; + } + + private final String path; + + @Activate + public MyService(Config config) { + this.path = config.path(); + } + + public String getPath() { + return path; + } + } + +A companion unit test in JUnit 5 might look like this: + + #!java + import org.apache.sling.testing.mock.osgi.config.annotations.ApplyConfig; + import org.apache.sling.testing.mock.osgi.config.annotations.UpdateConfig; + import org.apache.sling.testing.mock.osgi.junit5.OsgiConfigParametersExtension; + import org.junit.jupiter.api.Test; + import org.junit.jupiter.api.extension.ExtendWith; + + import static org.junit.jupiter.api.Assertions.assertEquals; + + @ExtendWith(OsgiConfigParametersExtension.class) + class MyServiceTest { + + @Test + @MyService.Config(path = "/apps") // requires @Retention(RetentionPolicy.RUNTIME) + void getPath(MyService.Config config) { + MyService myService = new MyService(config); + assertEquals("/apps", myService.getPath()); + } + + @Test + @ApplyConfig(type = MyService.Config.class, property = "path=/libs") + void getPath_applyConfig(MyService.Config config) { + MyService myService = new MyService(config); + assertEquals("/libs", myService.getPath()); + } + + @Test + @UpdateConfig(pid = "new-pid", property = "path=/content") + @ApplyConfig(pid = "new-pid", type = MyService.Config.class) + void getPath_updateConfig(MyService.Config config) { + MyService myService = new MyService(config); + assertEquals("/content", myService.getPath()); + } + } + + +### JUnit 4: Config Collector JUnit Rule + +Given the same example OSGi component from before: + + #!java + import org.osgi.service.component.annotations.Activate; + import org.osgi.service.component.annotations.Component; + import java.lang.annotation.Retention; + import java.lang.annotation.RetentionPolicy; + + @Component(service = MyService.class) + public class MyService { + + // specify runtime retention to allow for direct usage in unit tests + @Retention(RetentionPolicy.RUNTIME) + public @interface Config { + String path() default "/"; + } + + private final String path; + + @Activate + public MyService(Config config) { + this.path = config.path(); + } + + public String getPath() { + return path; + } + } + + +A companion unit test in JUnit 4 might look like this: + + #!java + import org.apache.sling.testing.mock.osgi.config.annotations.ApplyConfig; + import org.apache.sling.testing.mock.osgi.config.annotations.UpdateConfig; + import org.apache.sling.testing.mock.osgi.junit.ConfigCollector; + import org.apache.sling.testing.mock.osgi.junit.OsgiContext; + import org.apache.sling.testing.mock.osgi.junit.OsgiContextBuilder; + import org.junit.Rule; + + import static org.junit.Assert.assertEquals; + + public class MyServiceTest { + + @Rule + public OsgiContext context = new OsgiContextBuilder().build(); + + @Rule + public ConfigCollector configs = new ConfigCollector(context, MyService.Config.class); + + @Test + @MyService.Config(path = "/apps") // requires @Retention(RetentionPolicy.RUNTIME) + public void myServiceMethod() { + MyService.Config config = configs.configStream(MyService.Config.class) + .findFirst() + .orElseThrow(); + MyService myService = new MyService(config); + assertEquals("/apps", myService.getPath()); + } + + @Test + @ApplyConfig(type = MyService.Config.class, property = "path=/libs") + public void myServiceMethod() { + MyService.Config config = configs.configStream(MyService.Config.class) + .findFirst() + .orElseThrow(); + MyService myService = new MyService(config); + assertEquals("/libs", myService.getPath()); + } + + @Test + @UpdateConfig(pid = "new-pid", property = "path=/content") + @ApplyConfig(pid = "new-pid", type = MyService.Config.class) + public void myServiceMethod() { + MyService.Config config = configs.configStream(MyService.Config.class) + .findFirst() + .orElseThrow(); + MyService myService = new MyService(config); + assertEquals("/content", myService.getPath()); + } + } + +### Config Annotations: SlingContext Compatibility + +The OSGi Mock Config Annotations and JUnit4/JUnit5 extensions are compatible with the `SlingContext` from Sling Mocks and other libraries that provide extensions of `OsgiContextImpl`. + +To setup a project with Sling Mocks and OSGi Mocks Config Annotations, adjust the project pom.xml for either JUnit4 or JUnit5: + +For JUnit 5: + + #!xml + <dependency> Review Comment: I had checked `sling-mock.junit5` for a dependency on `osgi-mock.junit5`, but [it doesn't have one](https://github.com/apache/sling-org-apache-sling-testing-sling-mock/blob/852f247e0c6ef7ed92f8e2684ea1d15c41e1a672/junit5/pom.xml#L37-L49). I just assumed that `sling-mock.junit4` was the same situation, but upon checking it now, I see that [it does have an osgi-mock.junit4 dependency](https://github.com/apache/sling-org-apache-sling-testing-sling-mock/blob/852f247e0c6ef7ed92f8e2684ea1d15c41e1a672/junit4/pom.xml#L51-L55). So really, no additional maven configuration should be necessary for use of Config Annotations with either `sling-mock.junit4` or `sling-mock.junit5`, but we'll need to update the `sling-mock.junit5` pom.xml so that it follows this expectation. It looks like the same situation with [aem-mock.junit4](https://github.com/wcm-io/io.wcm.testing.aem-mock/blob/8606c9d8b98cd844ba79b31b2fc56b4706b898e0/junit4/pom.xml#L61-L85) and [aem-mock.junit5](https://github.com/wcm-io/io.wcm.testing.aem-mock/blob/8606c9d8b98cd844ba79b31b2fc56b4706b898e0/junit5/pom.xml#L68), so a similar change should be applied to `aem-mock.junit5`'s pom.xml. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
