Kong / unirest-java

Unirest in Java: Simplified, lightweight HTTP client library.
http://kong.github.io/unirest-java/
MIT License
2.61k stars 594 forks source link

Create A Mocking & Testing Lib To Compliment Unirest #265

Closed ryber closed 4 years ago

ryber commented 5 years ago

Is your feature request related to a problem? Please describe. As a developer who practices TDD I want to be able to easily unit test with unirest.

Describe the solution you'd like A testing library that can be used to test with unirest. Ideally I'd like to be able to set request expectations and responses or to verify requests were made and formatted as I expected.

Describe alternatives you've considered There are Apache Http Client mocking libraries that can be used but require configuring Unirest in more complicated ways. This library should feel native

tipsy commented 5 years ago

@ryber I'm using Unirest to test my web framework (https://javalin.io/).

A typical test looks like this:

@Test
fun `pathParam() works for multiple params`() = TestUtil.test { app, http ->
    app.get("/:1/:2/:3") { ctx -> ctx.result(ctx.pathParam("1") + ctx.pathParam("2") + ctx.pathParam("3")) }
    assertThat(http.getBody("/my/path/params")).isEqualTo("mypathparams")
}

The test() method creates a Javalin server, starts it, and passes the port to the http object (a class which contains a few Unirest convenience methods). After running the code in the lambda, it shuts down the server. I run 300 of these tests (+ some slower WebSocket tests) in about 10s.

Check out the test setup in Javalin, I think you might be happy with a similar approach. You could copy a bunch of Javalin's tests into the Unirest repo, they're really testing Unirest just as much as they're testing Javalin :)

By the way, I'm happy that you've started working on Unirest. I've been stuck on an old version for a very long time. At one point I forked it myself, and I was surprised to learn that the the tests were making real calls to the internet. I suppose that's something you want to fix with this issue?

ryber commented 5 years ago

@tipsy boy are you in for a treat. I already did this! Check out our totally awesome test BDD test suite:

https://github.com/Kong/unirest-java/tree/master/unirest/src/test/java/BehaviorTests

These tests use Java Spark (Javalin is a fork of Spark I believe, also not to be confused with Apache Spark).

In any case we stand up a server which mostly just echo's back the request but can also have custom responses and such. It's here: https://github.com/Kong/unirest-java/blob/master/unirest/src/test/java/BehaviorTests/MockServer.java

Additionally the response object has lots of built in assertions so we can do super cool things like:

 @Test
    public void testGetQueryStrings() {

       Unirest.get(MockServer.GET)
                .queryString("name", "mark")
                .queryString("nick", "thefosk")
                .asObject(RequestCapture.class)
                .getBody()
                .assertParam("name", "mark")
                .assertParam("nick", "thefosk");
    }

This was actually the very first thing I did when I started to maintain it. Yes, agree, calling external web services in unit tests was gross. Our BDD tests run amazingly fast. We are clearly of like mind.

This issue is for folks that don't want to go to to that extent. I think there is still value in a non-I/O solution, I was just going to make a simple wrapper for something like this: https://github.com/PawelAdamski/HttpClientMock

tipsy commented 5 years ago

That's great @ryber, definitely a great improvement over the old setup! I would have preferred an isolated integration test setup (no statics), with each component owning their domain (server for server things, client for client things, and an assertion library for assertion things), but the tests in your suite do look very neat !

These tests use Java Spark (Javalin is a fork of Spark I believe, also not to be confused with Apache Spark).

It started as one at least, but untangling it turned out to be more work than writing it from scratch.

This issue is for folks that don't want to go to to that extent. I think there is still value in a non-I/O solution.

I see! I should have checked out the current codebase before commenting, I just had a flashback to seeing the old tests and wanted to help. Anyway, thanks for taking control of the project, we were discussing moving away from Unirest at work (and in Javalin), but that's been put on hold now :)

ryber commented 4 years ago

released in 3.11.00

<dependency>
    <groupId>com.konghq</groupId>
    <artifactId>unirest-mocks</artifactId>
    <version>3.11.00</version>
    <scope>test</scope>
</dependency>