{"id":18841218,"url":"https://github.com/dcm4che/warpunit","last_synced_at":"2025-04-14T07:08:25.774Z","repository":{"id":6065930,"uuid":"54485900","full_name":"dcm4che/WarpUnit","owner":"dcm4che","description":"A lightweight framework for grey-box testing of server-side Java applications that allows to execute code on an application server from standalone JUnit tests","archived":false,"fork":false,"pushed_at":"2022-06-24T01:26:23.000Z","size":38,"stargazers_count":6,"open_issues_count":2,"forks_count":7,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-04-14T07:08:21.971Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dcm4che.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-03-22T15:20:21.000Z","updated_at":"2020-01-01T22:01:44.000Z","dependencies_parsed_at":"2022-09-15T09:51:23.074Z","dependency_job_id":null,"html_url":"https://github.com/dcm4che/WarpUnit","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dcm4che%2FWarpUnit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dcm4che%2FWarpUnit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dcm4che%2FWarpUnit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dcm4che%2FWarpUnit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dcm4che","download_url":"https://codeload.github.com/dcm4che/WarpUnit/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248837281,"owners_count":21169374,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-08T02:50:26.276Z","updated_at":"2025-04-14T07:08:25.748Z","avatar_url":"https://github.com/dcm4che.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"WarpUnit\n--------\n\nWarpUnit is a lightweight framework for gray-box integration testing of server side Java EE applications. \n\nIt 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.\n\n## Example\n\nLet's say we have a service with the following interface in our application   \n\n``` java  \npublic interface Greeter {\n    String greet(String whomToGreet);\n}\n```\n\nAnd we have a CDI bean that implements it  \n\n``` java \n@ApplicationScoped\npublic class PoliteGreeter implements Greeter {\n    @Override\n    public String greet(String whomToGreet) {\n        return \"Greetings, \" + whomToGreet + \" !\";\n    }\n}\n```\nNow let's say we want to test this service, and we want to test how it behaves directly on the application server. \nConsider that we don't have this service exposed e.g. through a RESTful service, so we cannot make a \"black-box\" test for it. \n\nWarpUnit can help here:\n   \n``` java \npublic class GreeterGrayBoxTest {\n \n    @Inject\n    Greeter greeter;\n \n    @Test\n    public void testGreeter() {\n \n        System.out.println(\"This is printed in the JUnit test output\");\n \n        WarpGate gate = WarpUnit.builder()\n                .primaryClass(GreeterGrayBoxTest.class)\n                .createGate();\n \n        String greetingForBob = gate.warp(() -\u003e {\n            System.out.println(\"This is printed in the server log\");\n            return greeter.greet(\"Bob\");\n        });\n \n        Assert.assertEquals(\"Greetings, Bob !\",greetingForBob);\n    }\n}\n``` \n\nThis 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.\n\nSo, what happens here?\n\n`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.\n\nThis 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.\n\nTo 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**.  \n\nYou will find this complete example in [warpunit-examples/greeter](https://github.com/dcm4che/WarpUnit/tree/master/warpunit-examples/greeter)\n\n## 2 flavours\n\nThere are 2 'flavours' of syntax that essentially do the same under the hood:  \n\n#### Lambda-style \n\nLambda-style is more concise/flexible. Useful when your test code tends to perform many \"small\" warps.  \n\n``` java\n\n@Inject\nGreeter greeter;\n\n...\n\nWarpGate gate = WarpUnit.builder()\n        .primaryClass(LambdaStyleGreeterTest.class)\n        .createGate();\n\nString greetingForBob = gate.warp(() -\u003e {\n    return greeter.greet(\"Bob\");\n});\n``` \n\n\n#### Proxy-style\n\nProxy 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.      \n\n``` java\nGreeterInsider proxyGate = WarpUnit.builder()\n        .primaryClass(GreeterInsiderImpl.class)\n        .includeInterface(true)\n        .createProxyGate(GreeterInsider.class);\n\nString greetingForBob = proxyGate.getAGreeting(\"Bob\");\n\n```\n\n``` java\npublic interface GreeterInsider {\n    String getAGreeting(String forWhom);\n}\n```\n\n``` java\npublic class GreeterInsiderImpl implements GreeterInsider {\n\n    @Inject\n    Greeter greeter;\n\n    @Override\n    public String getAGreeting(String forWhom) {\n        System.out.println(\"This is printed in the server log\");\n        return greeter.greet(forWhom);\n    }\n}\n```\n\n## Current status/limitations\n\n- Tested with Jboss/Wildfly app servers\n- Supports java 8\n- Lambdas allowed\n- Anonymous classes are not allowed. \n- Inner classes (but not inner-of-inner) allowed.\n  \n## How it works in a nutshell\n\nWhenever you warp something from the client code, the following happens:\n  \nOn the client  \n  \n- WarpUnit collects the bytecodes of the class that is warp'd (and it's inner classes)\n- Bytecodes are serialized and are sent to the server, along with the info of which method with which parameters should be called\n\nOn the server\n\n- The WarpUnit insider deployment receives a RESTful call with all this data \n- The received bytecodes are passed to a classloader and an object of a warp'd class is instantiated on the server \n- CDI injection is performed upon this instance, so all the fields with `@Inject`, `@Resource`, etc annotations are initialized\n- The specified method is invoked with the provided parameters\n- The return value of the method invocation (or an exception if thrown during execution) is sent as a response of a RESTful service\n\nBack on the client\n\n- The response is returned as an invocation result (or, in case of unsuccessful invocation, a `RemoteExecutionException` is thrown )\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdcm4che%2Fwarpunit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdcm4che%2Fwarpunit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdcm4che%2Fwarpunit/lists"}