Code Monkey home page Code Monkey logo

warpunit's Introduction

WarpUnit

WarpUnit is a lightweight framework for gray-box integration testing of server side Java EE applications.

It allows to use simple JUnit to make tests where some parts of the code are executed on an application server directly inside your Java EE application archive. First, this approach allows to avoid extensive mocking, and second, it reduces the risk of missing some deployment aspects while testing.

Example

Let's say we have a service with the following interface in our application

public interface Greeter {
    String greet(String whomToGreet);
}

And we have a CDI bean that implements it

@ApplicationScoped
public class PoliteGreeter implements Greeter {
    @Override
    public String greet(String whomToGreet) {
        return "Greetings, " + whomToGreet + " !";
    }
}

Now let's say we want to test this service, and we want to test how it behaves directly on the application server. Consider that we don't have this service exposed e.g. through a RESTful service, so we cannot make a "black-box" test for it.

WarpUnit can help here:

public class GreeterGrayBoxTest {
 
    @Inject
    Greeter greeter;
 
    @Test
    public void testGreeter() {
 
        System.out.println("This is printed in the JUnit test output");
 
        WarpGate gate = WarpUnit.builder()
                .primaryClass(GreeterGrayBoxTest.class)
                .createGate();
 
        String greetingForBob = gate.warp(() -> {
            System.out.println("This is printed in the server log");
            return greeter.greet("Bob");
        });
 
        Assert.assertEquals("Greetings, Bob !",greetingForBob);
    }
}

This is a simple JUnit test that you can run within your IDE or with e.g. maven surefire. You need a running server with you application deployed.

So, what happens here?

WarpGate is basically a destination where you "warp" your code to run it. You create a gate that is bound to a server (by default it's a server that is running on localhost) and you can run code from your test classes upon this gate (i.e. on that server). WarpUnit sends this code over to the server and executes it directly inside you application. You can therefore write some test code just like you would do it if it was part of your application, e.g. you can @Inject your CDI/EJB beans, use EntityManager, etc. In the 'client' code you can pass values/see return values and catch exceptions from the server side.

This way you can test your application as is i.e. with no need for mocking, and at the same time test against low-level interfaces/fine-grain services that are not normally exposed.

To be able to execute warpunit tests against a server, you need to include a special warpunit-insider.war into your *.ear under test. You can do it, e.g., with a maven profile to make sure that this war is only included into you application for the purpose of testing. Make sure it never ends up in production, or you are risking to have a backdoor for arbitrary code execution in you app.

You will find this complete example in warpunit-examples/greeter

2 flavours

There are 2 'flavours' of syntax that essentially do the same under the hood:

Lambda-style

Lambda-style is more concise/flexible. Useful when your test code tends to perform many "small" warps.

@Inject
Greeter greeter;

...

WarpGate gate = WarpUnit.builder()
        .primaryClass(LambdaStyleGreeterTest.class)
        .createGate();

String greetingForBob = gate.warp(() -> {
    return greeter.greet("Bob");
});

Proxy-style

Proxy style is more keystrokes and looks more complex, but is useful when you want to extract a "layer" of warp'able coarse-grain code parts, and have a clear separation of client/server test code.

GreeterInsider proxyGate = WarpUnit.builder()
        .primaryClass(GreeterInsiderImpl.class)
        .includeInterface(true)
        .createProxyGate(GreeterInsider.class);

String greetingForBob = proxyGate.getAGreeting("Bob");
public interface GreeterInsider {
    String getAGreeting(String forWhom);
}
public class GreeterInsiderImpl implements GreeterInsider {

    @Inject
    Greeter greeter;

    @Override
    public String getAGreeting(String forWhom) {
        System.out.println("This is printed in the server log");
        return greeter.greet(forWhom);
    }
}

Current status/limitations

  • Tested with Jboss/Wildfly app servers
  • Supports java 8
  • Lambdas allowed
  • Anonymous classes are not allowed.
  • Inner classes (but not inner-of-inner) allowed.

How it works in a nutshell

Whenever you warp something from the client code, the following happens:

On the client

  • WarpUnit collects the bytecodes of the class that is warp'd (and it's inner classes)
  • Bytecodes are serialized and are sent to the server, along with the info of which method with which parameters should be called

On the server

  • The WarpUnit insider deployment receives a RESTful call with all this data
  • The received bytecodes are passed to a classloader and an object of a warp'd class is instantiated on the server
  • CDI injection is performed upon this instance, so all the fields with @Inject, @Resource, etc annotations are initialized
  • The specified method is invoked with the provided parameters
  • The return value of the method invocation (or an exception if thrown during execution) is sent as a response of a RESTful service

Back on the client

  • The response is returned as an invocation result (or, in case of unsuccessful invocation, a RemoteExecutionException is thrown )

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.