perwendel / spark

A simple expressive web framework for java. Spark has a kotlin DSL https://github.com/perwendel/spark-kotlin
Apache License 2.0
9.64k stars 1.56k forks source link

Add proper testing lib #1085

Open kamilgregorczyk opened 5 years ago

kamilgregorczyk commented 5 years ago

Hi, It would be great if we could unitest spark directly through controllers, not by running whole server in-memory. Currently it's impossible to create custom request&response objects as constructors are protected.

laliluna commented 5 years ago

I were not happy with the consequence of writing routes differently for unit testing as well.

I proofed a concept here https://github.com/laliluna/spark-mock-demo

The idea is to replace the service with a mock which allows to run tests without the server.

    @Before
    public void setup() {
      SparkBuilder.initMock();
      SparkApplication app = new SparkApplication();
      app.init();
    }
    @Test
    public void getReturnsEmptyArray() {
      SparkClient client = MockSpark.getClient();
      Response response = client.get("/hello");
      assertEquals(200, response.status());
          assertEquals("[]", response.body());
    }

In order to implement this, we would need to make the service extend an interface and be swappable with a mock implementation. The classes SparkBuilder, MockSpark is only needed in the demo as the service is final.

If the idea is welcomed, I could try to implement this.

StuAtGit commented 5 years ago

A couple things:

So while there are nice reasons to have a Spark Service class that you hand dependencies too (which you could then mock()), instead of having them created on the fly (as an option! the current behavior as the default behavior is nice too), I'm not sure what testing value you'd get out of this, other than enabling badly written tests. Maybe if there was a good example of a well-written test that this enabled, the design would be more clear.

StuAtGit commented 5 years ago

Currently it's impossible to create custom request&response objects as constructors are protected.

This actually seems like the core of the issue.. however, the statement is also wrong, because you can mock Request & Response objects (e.g. with mockito).

I just verified with a test like so:

    @Test
    public void shouldAnswerWithTrue()
    {
        this.httpTestHandlerService.handleTestRequest(
            mock(Request.class),
            mock(Response.class)
        );
    }

Latest version, 2.9.1