Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WireMock with JUnit 5 #684

Closed
wonha opened this issue Jun 9, 2017 · 64 comments
Closed

WireMock with JUnit 5 #684

wonha opened this issue Jun 9, 2017 · 64 comments

Comments

@wonha
Copy link

wonha commented Jun 9, 2017

In JUnit 5, @Rule and @ClassRule is superseded by @ExtendWith, which requires extension class.
And it seems like extension for WireMock is not yet supported.
Is there any alternative way to use WireMock with stubbing and verification via JUnit 5?

@tomakehurst
Copy link
Member

You can programmatically start and stop WireMockServer. That's all the rule is doing really.

I'll mark this as a feature request as JUnit 5 support should start to be a priority soon.

@wonha
Copy link
Author

wonha commented Jun 9, 2017

Thank you for your comment, and marking.
Actually, I tried to use WireMock with JUnit, and there was no other way to do it without using JUnit 4.x Rule.
Thanks !

@tomakehurst
Copy link
Member

You can use @Before and @After annotated methods to start and stop a WireMockServer in JU4.

@tomakehurst
Copy link
Member

Some of WireMock's own acceptance tests actually do this in their base class, so might be worth checking that out if you're not sure what I mean.

@wonha
Copy link
Author

wonha commented Jun 9, 2017

Thanks for your kind comment. I'll check it.

@lanwen
Copy link

lanwen commented Jun 13, 2017

Please look at https://github.com/lanwen/wiremock-junit5 (will be available in maven central soon)

@sta-szek
Copy link

@lanwen nice! Could you do this as class level fields instead of (or additionally) method parameters?

@lanwen
Copy link

lanwen commented Jun 14, 2017

@sta-szek Like a class rule?

@sta-szek
Copy link

@lanwen exactly - just to simplify as much as possible.

@wonha
Copy link
Author

wonha commented Jun 28, 2017

@lanwen thanks for the nice code!

@JensPiegsa
Copy link

https://github.com/JensPiegsa/wiremock-extension

@lanwen
Copy link

lanwen commented May 9, 2018

What the difference?

@JensPiegsa
Copy link

It's an approach that uses annotated fields. See ExampleTest

@goyalashish
Copy link

@lanwen can you help me how to wiremock-junit5 for custom port.
As in your code, as per my understanding, we can get any random port, but if you want a specific port for wiremock, can you specify how to do that.

void function(@WiremockResolver.Wiremock WireMockServer server) throws IOException {
....
}

but in this, i can't set server port for which server need to start,
I was checking the code of wiremockResolver, this was the code,
this.server = new WireMockServer(((WiremockConfigFactory)mockedServer.factory().newInstance()).create());
i guess, due to this.. i am unable to specify some specific port.

Is there is any way to do that ?
Please unicast me

@ghilainm
Copy link

You can programmatically start and stop WireMockServer. That's all the rule is doing really.

I'll mark this as a feature request as JUnit 5 support should start to be a priority soon.

Any news about this?

@jmayday
Copy link

jmayday commented Mar 3, 2019

@ghilainm for me rewriting rule to Junit5 extension looks like this: https://github.com/jmayday/wiremock/commit/908cbb20d19cf7dcabcca3de28a2712fd895e472 (I'm not sure if it satisfies requirements for pull request though... @tomakehurst?)

As server starts on random port, we need to build also a webclient with correct url. It might be achieved in beforeAll method in a test class:

  @BeforeAll
  static void setup(@ServerUrl String serverUrl) {
    // build webclient using server url
  }

@tomakehurst
Copy link
Member

I'm a bit reticent about making WireMock dependent on both JUnit 4 and 5. Dropping 4 isn't an option at the moment as it's still pretty widely used.

Do you think there's much disadvantage in adding JUnit 5 support via a separate library?

@behrangsa
Copy link

Do you think there's much disadvantage in adding JUnit 5 support via a separate library?

Yes, an official but optional library should be quite helpful.

@luolong
Copy link

luolong commented Apr 9, 2019

What about splitting Wiremock library in two -- wiremock-core and wiremock-junit4 and adding wiremock-jupiter for JUnit 5 support?

The wiremock library could then simply have a dependency on core and junit4 for the sake of legacy users?

@tomakehurst
Copy link
Member

@luolong that doesn't sound much different from what we have now, if you consider @lanwen's library to be the jupiter version.

@t1
Copy link

t1 commented Sep 1, 2019

Having an 'official' Wiremock JUnit5 extension would be valuable. I actually expected to find a JUnit 5 extension when I have a JUnit 4 rule. And I think an optional dependency on JUnit 5 would be no problem at all, would it?

@t1 t1 mentioned this issue Sep 1, 2019
5 tasks
@luolong
Copy link

luolong commented Sep 2, 2019

@tomakehurst Sure, I realize that this is not so much different from what you have now. This is by design.

The only difference is that JUnit 4 dependency is explicitly divorced from the core dependency.
The separate modules could even share the same repository and release schedule.

Should not be difficult to achieve.

@tomakehurst
Copy link
Member

I'm coming around to the idea of making both JUnit 4 and 5 optional/provided dependencies. I'm going to look at this (with the usual caveats about being busy and it not happening quickly).

@blocha
Copy link

blocha commented Jan 29, 2020

Any update on this?

@JcMinarro
Copy link

Any update on this?
Currently, I am using @JensPiegsa implementation, but would be great to have an "official" artifact from Wiremock repository.

@fransflippo
Copy link

@tomakehurst Is this something any of us could help with? I can imagine splitting out the junit4 dependencies can be a hairy task with some architectural impact, so I would understand if you want to do it yourself since Wiremock is your baby :-)
But otherwise, let us know!

@blocha
Copy link

blocha commented Mar 17, 2020

@fransflippo @tomakehurst I would recommend using:

@AutoConfigureWireMock from our friends from spring's 'org.springframework.cloud:spring-cloud-contract-wiremock' - it's working great with Junit5 and you can customize it it you want :)

Patouche added a commit to Patouche/wiremock that referenced this issue Mar 30, 2021
Patouche added a commit to Patouche/wiremock that referenced this issue Apr 15, 2021
@rieckpil
Copy link

rieckpil commented Apr 22, 2021

Great to see @Patouche step in to add a JUnit Jupiter extension 🚀

In the meantime and for those who are looking for a solution to start WireMock before all test methods (as far as I can see it, no community extension allows this as they are implementing the BeforeEachCallback) especially when writing tests that involve a SpringTestContext where one wants to set e.g. the base URL prior to starting the application, I used the following setup over the past months:

public class WireMockInitializer 
  implements ApplicationContextInitializer<ConfigurableApplicationContext> {
 
  @Override
  public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
    WireMockServer wireMockServer = new WireMockServer(new WireMockConfiguration().dynamicPort());
    wireMockServer.start();
 
    configurableApplicationContext
      .getBeanFactory()
      .registerSingleton("wireMockServer", wireMockServer);
 
    configurableApplicationContext.addApplicationListener(applicationEvent -> {
      if (applicationEvent instanceof ContextClosedEvent) {
        wireMockServer.stop();
      }
    });
 
    TestPropertyValues
      // override any base URL of your HTTP clients here
      .of(Map.of("todo_base_url", "http://localhost:" + wireMockServer.port()))
      .applyTo(configurableApplicationContext);
  }
}

With the initializer above you'll start WireMock as part of the bootstrapping phase of the Spring Context, register it as a Spring Bean and can override base URLs for your HTTP clients.

Next, you need to activate/include this initializer with @ContextConfiguration:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ContextConfiguration(initializers = {WireMockInitializer.class})
class TodoControllerIT {
 
  @Autowired
  private WireMockServer wireMockServer;
 
  @AfterEach
  public void afterEach() {
    this.wireMockServer.resetAll();
  }
}

You can find a detailed explanation as part of this blog post.

@p7u
Copy link

p7u commented Aug 7, 2021

Hello,

If you're ok with that, I can try to add this feature in WireMock.

Recently, I have setup WireMock in a project at work. I was a little bit surprised that this is not already part of WireMock and we need to add an other library to add this kind of extension.

First at all, I took a look of some repositories such as :

It gave my some inspiration but I found that each extensions had some missing features. For example, none of these 3 JUnit extensions allow you to have an alternative between constructor injection, field injection or method injection.

For the configuration, somes extension didn't seem very clear to me. However, there are great ideas in each of these community extensions.

I can try to put all ideas together and maybe to add new one to have an official JUnit 5 extension for WireMock.

What do you think of that ?

So @Patouche any news?

@tomakehurst
Copy link
Member

Hey folks, I've been working on this. I think it's pretty much ready to go, but I'd appreciate any feedback I can get before I release it.

Please take a look at the docs on the branch if you're interested: #1439 (comment)

I've also pushed a standalone build here if you'd like to try it: https://github.com/tomakehurst/wiremock/releases/tag/2.31.0-beta

@beatngu13
Copy link

@tomakehurst I just gave it a try. Unfortunately, the beta version is not available on central and JitPack has issues building the project. So I downloaded the JAR and added it to my local repo:

mvn install:install-file \
        -Dfile=wiremock-jre8-standalone-2.31.0-beta.jar \     
        -DgroupId=com.github.tomakehurst \
        -DartifactId=wiremock-jre8 \
        -Dversion=2.31.0-beta \
        -Dpackaging=jar

Works like a charm, almost like a drop-in replacement – great work!

Side note: it's JUnit 5, so you can remove the public modifiers from the docs.

@tomakehurst
Copy link
Member

Thanks for the feedback @beatngu13!

It's on my list to get JitPack working so should be easier with future betas.

@beatngu13
Copy link

@tomakehurst one suggestion: maybe use Options#DEFAULT_PORT (i.e. 8080) here in the extension, rather than defaulting to a random port. Then, the extension IMHO better aligns with WireMock's default behavior and the existing JUnit 4 rules; also users don't have to "fiddle" with @RegisterExtension and can use the more popular @ExtendWith annotation. (Convention over configuration, so to say…)

@tomakehurst
Copy link
Member

I agree it's less surprising to default to 8080, but OTOH it prevents you from running your tests in parallel without switching everything over to the programmatic form, which you tend to want to do only when you've got 100s of tests and your build is starting to feel slow.

Also, defaulting to the random port nudges developers to use the WireMock's base URL methods rather than "http://localhost:8080" + myPath, which seems like better practice to me.

I'm genuinely in two minds though, not least because I can see myself spending the next 5 years telling every other mailing list poster about the random port.

@tomakehurst
Copy link
Member

There's another possibility, arguably a middle way.

I've been thinking it'd be good to support automatic JVM proxy setup in a similar fashion to Hoverfly, whereby forward proxying is enabled and the JVM system properties for proxy config are set to point to it so that you can mock multiple domains in a single instance.

I wouldn't want to turn this on by default, but it'd be nice to have it available declaratively so I was wondering about creating a subclass to the extension that turns this option on e.g.

@ExtendWith(WireMockExtensionWithJvmProxy.class)

Perhaps we could also have something like:

@ExtendWith(WireMockExtensionRandomPort.class)

or if random port is kept as the the default:

@ExtendWith(WireMockExtensionPort8080.class)

Thoughts?

@beatngu13
Copy link

beatngu13 commented Aug 28, 2021

Ah, I see. Using a random port definitely makes sense when executing the tests concurrently. You also know your user base way better than I do and what default makes more sense.

Regarding WireMockExtensionRandomPort and WireMockExtensionPort8080, you could also do something like:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@ExtendWith(WireMockExtension.class)
public @interface WireMockTest {

    // null means random port
    Integer httpPort;

    // more core config properties

}

Which can be used like:

@WireMockTest
class DeclarativeWireMockTest { }

If a static port is desired:

@WireMockTest(httpPort = 8080)
class DeclarativeWireMockTest { }

@tomakehurst
Copy link
Member

Yes, that's much nicer isn't it. I'll go with that.

@tomakehurst
Copy link
Member

I've updated the branch to include this ☝️ now.
https://github.com/tomakehurst/wiremock/blob/junit-jupiter/docs-v2/_docs/junit-jupiter.md

I'm still trying to figure out a better way to publish a beta build than putting the standalone JAR on Releases. So far:

  1. JitPack won't work because there are build steps that rely on NPM.
  2. GitHub Packages won't work because it won't let you make Maven repos public (unauthenticated).
  3. Sonatype's OSS snapshots repo won't work because it's giving me unexplained 400 errors when I try to publish to it.

If anyone has any other ideas I'm all ears...

@szpak
Copy link

szpak commented Aug 29, 2021

  1. Sonatype's OSS snapshots repo won't work because it's giving me unexplained 400 errors when I try to publish to it.

Strange, it seems to be a client side problem. I have snapshots publishing in a few Gradle projects and it used to work fine.

Do you have some CI logs to take a look (and configuration in a branch)?

@tomakehurst
Copy link
Member

@szpak there's nothing useful in the logs really, just Could not PUT 'https://oss.sonatype.org/content/repositories/snapshots/com/github/tomakehurst/wiremock-jre8/2.31.0-beta-2/wiremock-jre8-2.31.0-beta-2.jar'. Received status code 400 from server: Bad Request.

Do you have a Gradle build file with working sonatype snapshot publishing you could share so I can compare?

@tomakehurst
Copy link
Member

OK, looks like the issue is that you have to actually have SNAPSHOT in the version (duh!).

I've pushed a 2.31.0-SNAPSHOT to the Sonatype snapshots repo now for those wanting to try it out. You'll need to use https://oss.sonatype.org/content/repositories/snapshots/ as the repo URL in your build.

@szpak
Copy link

szpak commented Aug 29, 2021

OK, looks like the issue is that you have to actually have SNAPSHOT in the version (duh!).

Yup, they have separate repos for snapshot and release versions and are strict about content. I'm glad you solved it!

@bmorris591
Copy link

bmorris591 commented Aug 31, 2021

There seems to be some issue with the setup of Gradle for the JUnit BOM. If you look at the pom you can see the following

<dependency>
    <groupId>org.junit</groupId>
    <artifactId>junit-bom</artifactId>
    <version>5.7.1</version>
    <scope>runtime</scope>
</dependency>

i.e. it adds the BOM as the runtime dependency rather than in the dependencyManagement section and the scope is runtime not import.

Not sure if this is a Gradle bug or an issue with the configuration in the build

It makes downstream Gradle builds unhappy (running Gradle 7.2)

> Could not resolve all files for configuration ':testRuntimeClasspath'.
   > Could not resolve org.junit:junit-bom:5.7.1.
     Required by:
         project : > com.github.tomakehurst:wiremock-jre8:2.31.0-SNAPSHOT:20210829.210337-1
      > No matching variant of org.junit:junit-bom:5.7.2 was found. The consumer was configured to find a runtime of a library compatible with Java 16, packaged as a jar, preferably optimized for standard JVMs, and its dependencies declared externally, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'jvm' but:
          - Variant 'apiElements' capability org.junit:junit-bom:5.7.2:
              - Incompatible because this component declares an API of a platform and the consumer needed a runtime of a library
              - Other compatible attributes:
                  - Doesn't say anything about how its dependencies are found (required its dependencies declared externally)
                  - Doesn't say anything about its target Java environment (preferred optimized for standard JVMs)
                  - Doesn't say anything about its target Java version (required compatibility with Java 16)
                  - Doesn't say anything about its elements (required them packaged as a jar)
                  - Doesn't say anything about org.jetbrains.kotlin.platform.type (required 'jvm')
          - Variant 'enforcedApiElements' capability org.junit:junit-bom-derived-enforced-platform:5.7.2:
              - Incompatible because this component declares an API of an enforced platform and the consumer needed a runtime of a library
              - Other compatible attributes:
                  - Doesn't say anything about how its dependencies are found (required its dependencies declared externally)
                  - Doesn't say anything about its target Java environment (preferred optimized for standard JVMs)
                  - Doesn't say anything about its target Java version (required compatibility with Java 16)
                  - Doesn't say anything about its elements (required them packaged as a jar)
                  - Doesn't say anything about org.jetbrains.kotlin.platform.type (required 'jvm')
          - Variant 'enforcedRuntimeElements' capability org.junit:junit-bom-derived-enforced-platform:5.7.2 declares a runtime of a component:
              - Incompatible because this component declares an enforced platform and the consumer needed a library
              - Other compatible attributes:
                  - Doesn't say anything about how its dependencies are found (required its dependencies declared externally)
                  - Doesn't say anything about its target Java environment (preferred optimized for standard JVMs)
                  - Doesn't say anything about its target Java version (required compatibility with Java 16)
                  - Doesn't say anything about its elements (required them packaged as a jar)
                  - Doesn't say anything about org.jetbrains.kotlin.platform.type (required 'jvm')
          - Variant 'runtimeElements' capability org.junit:junit-bom:5.7.2 declares a runtime of a component:
              - Incompatible because this component declares a platform and the consumer needed a library
              - Other compatible attributes:
                  - Doesn't say anything about how its dependencies are found (required its dependencies declared externally)
                  - Doesn't say anything about its target Java environment (preferred optimized for standard JVMs)
                  - Doesn't say anything about its target Java version (required compatibility with Java 16)
                  - Doesn't say anything about its elements (required them packaged as a jar)
                  - Doesn't say anything about org.jetbrains.kotlin.platform.type (required 'jvm')

This is because Gradle "knows" that the BOM is a "platform" but it's being added as a dependency.

Excluding the dependency from Wiremock makes things happy

    testImplementation("com.github.tomakehurst:wiremock-jre8:2.31.0-SNAPSHOT") {
        exclude(group = "org.junit", module = "junit-bom")
    }

@tomakehurst
Copy link
Member

Thanks for reporting this.

Would you mind sharing your Gradle build file (or enough of it) so I can reproduce this?

Also, does this happen with Java versions < 16?

@bmorris591
Copy link

It's publicly available on the competing code hosting platform - https://gitlab.com/bmorris591/volvooncall-mysql

I've pushed up a branch without the exclusion to show the error, mainline has the exclusion and compiles happily.

CI/CD shows the error

@tomakehurst
Copy link
Member

Thanks for the detailed info @bmorris591!

I think I've figured out the solution, so I'll push another snapshot tomorrow.

@elect86
Copy link

elect86 commented Sep 1, 2021

@bmorris591 I could fix the Gradle synchronization with ::exclude, but if I try to run a test, I still get:

e: /home/elect/IdeaProjects/gradle-download-task/src/test/kotlin/de/undercouch/gradle/tasks/download/testBases.kt: (89, 22): Cannot access 'org.junit.rules.MethodRule' which is a supertype of 'com.github.tomakehurst.wiremock.junit.WireMockClassRule'. Check your module classpath for missing or conflicting dependencies
e: /home/elect/IdeaProjects/gradle-download-task/src/test/kotlin/de/undercouch/gradle/tasks/download/testBases.kt: (89, 22): Cannot access 'org.junit.rules.TestRule' which is a supertype of 'com.github.tomakehurst.wiremock.junit.WireMockClassRule'. Check your module classpath for missing or conflicting dependencies
e: /home/elect/IdeaProjects/gradle-download-task/src/test/kotlin/de/undercouch/gradle/tasks/download/testBases.kt: (94, 22): Cannot access 'org.junit.rules.MethodRule' which is a supertype of 'com.github.tomakehurst.wiremock.junit.WireMockClassRule'. Check your module classpath for missing or conflicting dependencies
e: /home/elect/IdeaProjects/gradle-download-task/src/test/kotlin/de/undercouch/gradle/tasks/download/testBases.kt: (94, 22): Cannot access 'org.junit.rules.TestRule' which is a supertype of 'com.github.tomakehurst.wiremock.junit.WireMockClassRule'. Check your module classpath for missing or conflicting dependencies

Is it the same to you?

@tomakehurst
Copy link
Member

New 2.31.0-SNAPSHOT pushed. This seems to fix the issue in your project @bmorris591.

@bmorris591
Copy link

That got a green build when I reran the spike linked above. Mainline build has also completed successfully after merge.

Thanks!

@alexsapps
Copy link
Contributor

Seems fixed and this works for me!
http://wiremock.org/docs/junit-jupiter/

At first I thought we still had to make our own extensions because this issue was still open. Posting the link above so others can find it too.

@tomakehurst
Copy link
Member

Good point, closed!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests