I’d like to test code that is attempting to signalWithStart a workflow (note: I’m not trying to test the workflow itself). The code under test has a dependency on WorkflowClient. Oversimplified example (Kotlin):
class ClientExample(
val client: WorkflowClient,
) {
fun sendStringAsSignal(workflowId: String, signalValue: String) {
val workflow = client.newWorkflowStub(
MyWorkflow::class.java,
WorkflowOptions.newBuilder()
.setTaskQueue("TaskQueue")
.setWorkflowId(workflowId)
.build()
)
WorkflowStub.fromTyped(workflow).signalWithStart(
"signalName",
arrayOf(signalValue),
arrayOf()
)
}
}
How can I test that my WorkflowStub was created with the correct arguments and that the workflow signal method was invoked with the correct arguments?
I cannot easily mock the client since I would need to heavily mock multiple layers: newWorkflowStub, static WorkflowStub.fromTyped, etc.
I see that Go has a Client mock but I don’t see any similar offering in the Java SDK (maybe mocking is more idiomatic in Go?).
Thanks again @maxim. I’m taking this approach now.
Some FYIs to anyone reading this in the future, and optionally as feedback to Temporal team:
It looks like TestWorkflowExtension doesn’t currently support configuring the task queue, but you can configure task queue with testEnv.newWorker when using the manual approach.
When invoking a workflow with signalWithStart, it doesn’t block for completion, nor does the returned WorkflowExecution offer an easy way to await the execution to finish. The best way that I could find was to construct a new workflow stub and to invoke the workflow in a blocking fashion.
I ultimately ended up with something like this (Kotlin):
val expectedTaskQueue = "ExpectedTaskQueue"
val testEnv = TestWorkflowEnvironment.newInstance()
val worker = testEnv.newWorker(expectedTaskQueue)
val client = testEnv.workflowClient
val myService = MyServiceImpl(client)
class TestWorkflowImpl : MyWorkflow {
var signaled = false;
override fun startWorkflow(input: MyWorkflowInput): MyWorkflowOutput {
val success = Workflow.await(Duration.ofSeconds(5)) { signaled }
if (!success) {
throw TimeoutException("Timed out waiting for signal")
}
return MyWorkflowOutput()
}
override fun signal(input: SignalInput) {
signaled = true
}
}
@BeforeEach
fun setUp() {
worker.registerWorkflowImplementationTypes(TestWorkflowImpl::class.java)
testEnv.start()
}
@AfterEach
fun tearDown() {
testEnv.close()
}
@Test
@Timeout(value = 10, unit = TimeUnit.SECONDS)
fun testSubmit() {
// Given
val input = UUID.randomUUID().toString()
// When
val workflowExecution = myService.submit(input)
// Await
val workflowStub = client.newUntypedWorkflowStub(workflowExecution.workflowId)
val workflowOutput = workflowStub.getResult<MyWorkflowOutput>()
// Then
assertThat(workflowExecution.workflowId).isEqualTo(...)
assertThat(workflowOutput).isEqualTo(MyWorkflowOutput())
}
Feedback welcome on any ways to simplify this, but it is cleaner than trying to mock WorkflowClient/WorkflowStub.