{"id":37020454,"url":"https://github.com/netmikey/testprocesses","last_synced_at":"2026-01-14T02:18:43.579Z","repository":{"id":148319522,"uuid":"580812664","full_name":"netmikey/testprocesses","owner":"netmikey","description":"A Java library that manages the lifecycle of applications/programs (processes) needed during testing.","archived":false,"fork":false,"pushed_at":"2025-10-17T06:03:39.000Z","size":278,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-18T09:18:55.338Z","etag":null,"topics":["java","junit","junit-extension","process","testing","testing-library"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/netmikey.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-12-21T14:11:07.000Z","updated_at":"2025-10-17T06:03:23.000Z","dependencies_parsed_at":"2025-10-17T21:03:40.056Z","dependency_job_id":"748815f9-dc9b-4591-8638-6177c3b5e0ec","html_url":"https://github.com/netmikey/testprocesses","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/netmikey/testprocesses","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netmikey%2Ftestprocesses","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netmikey%2Ftestprocesses/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netmikey%2Ftestprocesses/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netmikey%2Ftestprocesses/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/netmikey","download_url":"https://codeload.github.com/netmikey/testprocesses/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netmikey%2Ftestprocesses/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28408711,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T01:52:23.358Z","status":"online","status_checked_at":"2026-01-14T02:00:06.678Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["java","junit","junit-extension","process","testing","testing-library"],"created_at":"2026-01-14T02:18:42.925Z","updated_at":"2026-01-14T02:18:43.565Z","avatar_url":"https://github.com/netmikey.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"TestProcesses\n=============\n\n[![Build Status](https://github.com/netmikey/testprocesses/actions/workflows/build.yaml/badge.svg)](https://github.com/netmikey/testprocesses/actions)\n[![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.github.netmikey.testprocesses/testprocesses-core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.github.netmikey.testprocesses/testprocesses-core)\n\nA Java library that manages the lifecycle of applications/programs (processes) needed during testing.\n\n\n## Purpose\n\nWhen running integration-, functional- or blackbox-tests, it is often necessary to have additional processes running, besides the JVM actually executing the tests, that provide required functionality for the tests to be run. A few examples are:\n\n  - a shell-script or native non-Java application simulating a specific interface or business need\n  - the system-under-test when blackbox-testing[^1]\n\nTestProcesses enables managing one or more of these \"test processes\" for your tests declaratively.\n\n### When \u003cu\u003enot\u003c/u\u003e to use it\n\n- **Unit tests**\n\n  When you're testing isolated code on a small scale, you probably don't want to use TestProcesses. If you're trying to simulate/mock something on that level, you're probably looking for [Mockito](https://site.mockito.org) or some other Java mocking framework.\n\n- **Non-blackbox functional or integration tests**\n\n  In this case, it'll be much easier to have all or part of your application running directly besides your tests, e.g. using [Spring Integration Testing](https://docs.spring.io/spring-framework/docs/current/reference/html/testing.html#integration-testing).\n\n- **When there's a test library for the test-supporting feature you need**\n\n  When you need to test against mock/assertable variants of common services, chances are there's a Java testing library for that. If that's the case, you'll be far better off using these. Here are a few examples of test libraries for common services:\n\n  - **http server**: [WireMock](https://wiremock.org), [MockServer](https://www.mock-server.com/)\n  - **http proxy**: [LittleProxy](https://github.com/adamfisk/LittleProxy), [WireMock](https://wiremock.org), [MockServer](https://www.mock-server.com/)\n  - **smtp/pop3/imap email server**: [GreenMail](https://github.com/greenmail-mail-test/greenmail)\n\n\n- **When you can use Docker**\n  \n  In case your system-under-test or test-supporting process is available as Docker container, you should probably look into [TestContainers](https://www.testcontainers.org) (see the similarity in name? 😉)\n\n\n## Features\n\n  - Declarative and imperative using annotations or a Java API\n  - Test processes can be anything the OS can run\n  - A single test process only has to be defined once and can be reused by as many tests as neccessary\n  - A test-process is automatically started before a test if it is not running yet\n  - All running test-processes are automatically shut down (destroyed) before the JVM (or more precisely: Spring's Test Context) is shut down\n  - Different mechanisms can be used for detecting when a process has finished starting up and shutting down (e.g. TCP Port, text/pattern in logfile or stdOut/stdErr,...)\n  - Fine-grained control about whether a test process should continue running or be stopped / restarted between test methods\n  - A test process' stdOut/stdErr streams can be easily obtained to run assertions. Either the full stream (since the process started) can be returned or just the specific part that has been written during the current test method.\n  - It is possible to block the test thread while waiting for an event on the test-process (e.g. a log message on stdOut/stdErr/logFile, a TCP Port to be opened/closed,...)\n\n\n## Requirements\n\nIn order to use TestProcesses, currently you must be using:\n\n- JUnit Jupiter\n- Spring Test (ideally `spring-boot-starter-test`)\n\nThe following table describes the version compatibilities:\n\n| TestProcesses Version | Min. Java Version | Spring Boot Version |\n|-----------------------|-------------------|---------------------|\n| 1.x                   | 11                | 2.x                 |\n| 2.x                   | 17                | 3.x                 |\n\n\n## Installation\n\nTestProcesses is available as library in [Maven Central](https://search.maven.org/search?q=g:io.github.netmikey.testprocesses). Add TestProcesses to your project's dependencies by declaring a test-compile-time dependency:\n\n```gradle\nrepositories {\n    mavenCentral()\n}\n\ndependencies {\n    testImplementation(\"io.github.netmikey.testprocesses:testprocesses-core:1.0.0\")\n}\n```\n\n\n## Usage\n\n### Defining a test process\n\nBefore you can use a test-process, you will have to define it. To do so, you have to implement the `TestProcessDefinition` interface. Inheriting from `AbstractTestProcessDefinition`, while not mandatory, is highly recommended:\n\n```java\n@Component\npublic class MyTestProcess extends AbstractTestProcessDefinition {\n\n    public MyTestProcess() {\n        setStartupDetector(LogPatternEventDetector\n            .onStdOut()\n            .withMarker(\"My process has started\"));\n    }\n\n    @Override\n    protected void buildProcess(ProcessBuilder builder) {\n        builder.command(\"my-process\", \"-some\", \"argument\");\n    }\n\n}\n```\n\nIn the example above, we define a test process in a class `MyTestProcess`.\n\nIn the `buildProcess()` method, we obtain a [`ProcessBuilder`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/ProcessBuilder.html) instance. We will use it to define how our test process should be started.\n\nIn the constructor, we configure a \"startupDetector\". StartupDetector and ShutdownDetector returned by a `TestProcessDefinition` are used by the framework to detect when that test process has finished starting up or finished shutting down respectively. For both of them, `EventDetector` implementations are used. TestProcesses provides some `EventDetector`s out of the box:\n\n  - `LogPatternEventDetector`: detects the presence of marker strings or text matching a regular expression in log files or stdOur/stdErr streams.\n  - `TcpPortEventDetector`: detects when a given port has been opened or closed.\n  - `RecursiveProcessTerminationEventDetector`: detects when a test process has stopped running. This EventDetector is used by default as ShutdownDetector in `AbstractTestProcessDefinition`.\n\nIn the example above, we tell TestProcesses that whenever it starts the `MyTestProcess` definition, it should block and wait for the process to print the string \"My process has started\" on its stdOut stream before continuing the tests.\n\nFinally, note the presence of Spring's `@Component` annotation. Using this annotation will create an instance of the `MyTestProcess` definition and register it as singleton in Spring's test context. Registering a definition as Spring bean is one way to have TestProcesses find it when we want to use it later.\n\n\n### Using a test process for a test\n\nOnce a TestProcessDefinition has been created, we can tell TestProcesses to make sure it is running before starting a given test method:\n\n```java\n@Test\n@TestProcess(MyTestProcess.class)\npublic void testSomethingThatRequiresMyTestProcess() {\n    // my-process will be running here\n}\n```\n\n\u003e **Warning**\n\u003e\n\u003e Make sure to enable [auto-configuration](https://docs.spring.io/spring-boot/docs/current/reference/html/using.html#using.auto-configuration) in your Spring test context (e.g. by making sure you have [`@EnableAutoConfiguration`](https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/autoconfigure/EnableAutoConfiguration.html) declared).\n\nThere are a couple of ways to reference a `TestProcessDefinition`. Referencing it by its class will have TestProcesses look into the Spring Test Context to find a bean of that type (that's why we added `@Component` on `MyTestProcess` above).\n\nIt is also possible to use the Spring bean name (note that when using `@Component`, Spring uses the lowercased classname as bean name, which is what we use here):\n\n```java\n@Test\n@TestProcess(beanName = \"myTestProcess\")\npublic void testUsingTheBeanName() {\n    // my-process will be running here\n}\n```\n\n### Test process lifecycle\n\nUsing the `@TestProcess` annotation will have TestProcesses start the targetted `TestProcessDefinition` and make sure it is running before starting the annotated test method. By default, the test process will be left running so that it can be reused by multiple test methods. This avoids stopping and re-starting test processes between test methods, which significantly speeds up testing.\n\nIf you need more control over when a test process is stopped and/or restarted, you can specify that in the annotation:\n\n```java\n// The test process will be stopped immediately\n// after this test method\n@TestProcess(\n    beanClass = MyTestProcess.class,\n    stopStrategy = StopStrategy.STOP_AFTER_TEST)\n\n// Even if the test process is already running,\n// stop and restart it before starting this test\n@TestProcess(\n    beanClass = MyTestProcess.class,\n    startStrategy = StartStrategy.REQUIRE_RESTART)\n\n// Make sure to (re-)start the test process before\n// this test and to stop it immediately after this test\n@TestProcess(\n    beanClass = MyTestProcess.class,\n    startStrategy = StartStrategy.REQUIRE_RESTART,\n    stopStrategy = StopStrategy.STOP_AFTER_TEST)\n```\n\nFor even more fine-grained control, you will need to [use the API](#using-the-api).\n\n\n### Test process identifiers\n\nEach test process definition needs to provide a test process identifier. Identifiers are used as unique keys for detecting wheter a test process is already running or not: whenever a process with the same identifier is already running, the running process is stopped first before the new one is started, even if the default `StopStrategy.LEAVE_RUNNING` is used.\n\nThis enables you to have multiple mutually exclusive `TestProcessDefinition` implementations out of which *at most one* will be running at any time.\n\nAs a concrete example for when this might be useful: imagine a test process that needs to be started with different configuration or parameters for different sets of tests. You'd implement 2 `TestProcessDefinition`s with the same identifier. You could then annotate each test with whichever of the 2 `TestProcessDefinition`s it needs and TestProcesses would make sure the process is kept running as much as possible and restarted whenever necessary while never running more than once at a time.\n\nBy default, `AbstractTestProcessDefinition` uses the fully qualified implementation class name as identifier.\n\n\n### Using the API\n\nSometimes, you need even more control over test processes or you have special use cases. This is when the API comes in handy.\n\nThe main entry to TestProcesses API will be the `TestProcessesRegistry`. When [Spring Boot AutoConfiguration](https://docs.spring.io/spring-boot/docs/current/reference/html/using.html#using.auto-configuration) is in use, TestProcesses will automatically register its central `TestProcessesRegistry` instance with your Spring test context. You can then obtain a reference to it for example by simply `@Autowire`ing it in your Spring test class.\n\nThe `TestProcessesRegistry` has methods for starting and stopping test processes, using `EventDetector`s to wait for an event on a specific test process, obtaining a test process' stdOur/stdErr streams and more. Feel free to explore its API. Here is a basic example:\n\n```java\nimport static io.github.netmikey.testprocesses.TestProcessDefinitionBy.*;\n\n@SpringBootTest\n@EnableAutoConfiguration\npublic class MyTest {\n\n    @Autowired\n    private TestProcessesRegistry registry;\n\n    // Doesn't necessarily need to be a Spring bean\n    private MyTestProcess myTestProcess = new MyTestProcess();\n\n    @Test\n    public void testTestProcessesApi() {\n        // Start using a non-Spring TestProcessDefinition\n        registry.start(instance(myTestProcess), StartStrategy.USE_EXISTING);\n\n        // ... do something with my-process ...\n\n        /*\n         * Wait for my-process to output something like \"Operation\n         * ID:69 complete\" on stdOut.\n         * Will throw a TimeoutException if my-process doesn't print\n         * a matching string on its stdOut within 5 seconds.\n         */\n        registry.waitForEventOn(instance(myTestProcess),\n            LogPatternEventDetector\n                .onStdOut()\n                .withTimeoutMillis(5000)\n                .withPattern(\"Operation ID:[\\\\d]+ complete\"));\n\n        /* \n         * You can also test the streams' content (beware of chatty\n         * test processes as the streams' content will be loaded\n         * into memory.\n         */\n        Assertions.assertThat(\n            registry.stdOutAsStringOf(instance(myTestProcess)))\n                .contains(\"Something was successful.\");\n\n        // Stop the test process. Reference it using the definition type.\n        registry.stop(clazz(MyTestProcess.class));\n    }\n}\n```\n\nFor more examples, see the [functional tests](https://github.com/netmikey/testprocesses/tree/main/testprocesses-core/src/test/java/io/github/netmikey/testprocesses/functional) in the `testprocesses-core` module.\n\n\n### Automatically logging a process' stdOut/stdErr streams\n\nTestprocesses can automatically log the content of a test process' stdOut/stdErr streams. This can be done in 2 ways.\n\nTo log the full stdOut/stdErr streams of each process when it terminates, you can set the logger `io.github.netmikey.testprocesses.TestProcessesRegistry` to the `TRACE` level. This is useful to obtain diagnostic information if a process crashes on startup.\n\nAlternatively, you can extend your test(s) with the `io.github.netmikey.testprocesses.extensions.LogTestProcessesOutputExtension` JUnit Jupiter extension. This logs only the part of each process' stdOut/stdErr streams after each test that was emitted during that test. This is useful to associate the part of a testprocess' output with the exact test that caused it.\n\n```java\n@SpringBootTest\n@ExtendWith(LogTestProcessesOutputExtension.class)\n@TestProcess(SomeTestProcessDefinition.class)\npublic class MyTest {\n    // ...\n}\n```\n\n## Limitations\n\nBecause the framework tries to reuse running test processes between tests (if not told otherwise), a test process becomes a shared resource and is, by nature, quite stateful. Because of this, running tests in parallel will most probably not behave as expected.\n\n\n[^1]: **About blackbox testing**: When blackbox-testing, it's usually desirable to have the SUT as isolated as possible from the tests themselves. Running the SUT within the JVM that is also running your tests then isn't an option (classpath-, memory- and context pollution, different way ot launching, different behavior,...).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnetmikey%2Ftestprocesses","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnetmikey%2Ftestprocesses","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnetmikey%2Ftestprocesses/lists"}