
Test and run a Worker
- Build the application
- Test and run a Worker
- Run and observe retries
Now that the Workflow and Activities are in place, you'll configure a Worker to host them and write tests to verify they behave as expected. The Worker polls a Task Queue and runs your code when work arrives.
Configure and run a Worker
Now you can create the Worker program. Create the file worker.rb in the lib directory:
touch lib/worker.rb
Then open worker.rb in your editor and add the following code to define the Worker program:
require_relative 'ip_geolocate'
require 'temporalio/client'
require 'temporalio/worker'
# Create a client
begin
client = Temporalio::Client.connect('localhost:7233', 'default')
rescue StandardError => e
puts e.message
exit 1
end
# Create a worker with the client, activities, and workflows
worker = Temporalio::Worker.new(
client:,
task_queue: IPGeolocate::TASK_QUEUE_NAME,
workflows: [IPGeolocate::GetAddressFromIPWorkflow],
activities: [IPGeolocate::GetIPActivity, IPGeolocate::GetLocationActivity]
)
# Run the worker until SIGINT. This can be done in many ways, see "Workers" section for details.
worker.run(shutdown_signals: ['SIGINT'])
The code requires the ip_geolocate module, which includes your Workflow and Activity Definitions. It also uses the TASK_QUEUE_NAME constant.
You first create a client, and then you create a Worker that uses the client, along with the Task Queue it should listen on. By default, the client connects to the Temporal Service running at localhost on port 7233, and connects to the default namespace. You can change this by setting values in the Client Options.
In this case your Worker will run your Workflow and your two Activities, but there are cases where you could configure one Worker to run Activities, and another Worker to run the Workflows.
Now you'll start the Worker. Be sure you have started the local Temporal Service and execute the following command to start your Worker:
bundle exec ruby lib/worker.rb
Your Worker will then begin running and is polling the Temporal Service for Workflows to run, but before you start your Workflow, you'll write tests to prove it works as expected.
Write a Workflow test
The Temporal Ruby SDK includes methods that help you test your Workflow executions. Let's add a basic unit test to the application to make sure the Workflow works as expected.
You'll use the temporalio/testing package, which provides a WorkflowEnvironment that downloads and runs a lightweight test server.
Create a test directory:
mkdir test
Then create the file get_address_from_ip_workflow_test.rb within the test directory:
touch test/get_address_from_ip_workflow_test.rb
Add the following code to get_address_from_ip_workflow_test.rb to test the Workflow execution:
require 'test_helper'
require 'securerandom'
require 'temporalio/testing'
require 'temporalio/worker'
require 'ip_geolocate'
class GetAddressFromIPWorkflowTest < Minitest::Test
class MockGetIPActivity < Temporalio::Activity::Definition
activity_name :GetIPActivity
def execute
"1.1.1.1"
end
end
class MockGetLocationActivity < Temporalio::Activity::Definition
activity_name :GetLocationActivity
def execute(ip)
"Planet Earth"
end
end
def test_gets_location_from_ip_with_mocked_activities
Temporalio::Testing::WorkflowEnvironment.start_local do |env|
worker = Temporalio::Worker.new(
client: env.client,
task_queue: "test",
workflows: [IPGeolocate::GetAddressFromIPWorkflow],
activities: [MockGetIPActivity, MockGetLocationActivity],
workflow_executor: Temporalio::Worker::WorkflowExecutor::ThreadPool.default
)
worker.run do
result = env.client.execute_workflow(
IPGeolocate::GetAddressFromIPWorkflow,
"Testing",
id: "test-#{SecureRandom.uuid}",
task_queue: worker.task_queue
)
assert_equal 'Hello, Testing. Your IP is 1.1.1.1 and you are located in Planet Earth.', result
end
end
end
end
WorkflowEnvironment is a runtime environment used to test a Workflow. You use it to connect the Client and Worker to the test server and interact with the test server. You'll use this to register your Workflow Type and access information about the Workflow Execution, such as whether it completed successfully and the result or error it returned.
This test sets up a test environment to run Workflows that uses a lightweight Temporal Service specifically for testing. In the test itself, you create a Worker that connects to the test environment. This should look familiar, as it's similar to the code you wrote to define your Worker program.
Instead of using your actual Activities, you replace the Activities GetIPActivity and GetLocationActivity with methods that return hard-coded values. This way you're testing the Workflow's logic independently of the Activities. If you wanted to test the Activities directly as part of an integration test, you'd specify them directly as you did when you wrote the Worker program.
Run the test:
bundle exec ruby -Ilib:test test/get_address_from_ip_workflow_test.rb
The test environment starts, spins up a Worker, and executes the Workflow in the test environment. At the end, you'll see that your test passes:
Finished tests in 2.358264s, 0.4240 tests/s, 0.4240 assertions/s.
1 tests, 1 assertions, 0 failures, 0 errors, 0 skips
Write Activity tests
With a Workflow test in place, you can write unit tests for the Activities.
Both of your Activities make external calls to services that will change their results based on who runs them. It will be challenging to test these Activities reliably. For example, the IP address may vary based on your machine's location.
To ensure you can test the Activities in isolation, you'll stub out the HTTP calls. The ActivityEnvironment from the temporalio/testing package lets you test Activities as if they were part of a Temporal Application.
Create the file get_ip_activity_test.rb:
touch test/get_ip_activity_test.rb
Next, write the test for the GetIPActivity Activity:
require 'test_helper'
require 'securerandom'
require 'temporalio/testing'
require 'ip_geolocate/get_ip_activity'
class GetIPActivityTest < Minitest::Test
def test_gets_ip
env = Temporalio::Testing::ActivityEnvironment.new
Net::HTTP.stub(:get, ->(*) { "1.1.1.1" }) do
result = env.run(IPGeolocate::GetIPActivity)
assert_equal "1.1.1.1", result
end
end
end
Now, create a test file for get_location_activity_test.rb:
touch test/get_location_activity_test.rb
Next, write the test for the GetLocationActivity Activity, using Net::HTTP to stub out actual HTTP calls so your tests are consistent:
require "test_helper"
require 'securerandom'
require 'temporalio/testing'
require "ip_geolocate/get_location_activity"
class GetLocationActivityTest < Minitest::Test
def test_gets_ip
env = Temporalio::Testing::ActivityEnvironment.new
fake_location = {
city: 'Sample City',
regionName: 'Sample Region',
country: 'Sample Country'
}.to_json;
Net::HTTP.stub(:get, ->(*) { fake_location }) do
result = env.run(IPGeolocate::GetLocationActivity, "1.1.1.1")
assert_equal "Sample City, Sample Region, Sample Country", result
end
end
end
To test the Activity itself, you use the test environment to execute the Activity rather than directly calling the GetLocationActivity method. You get the result from the Activity Execution and then ensure it matches the value you expect.
This test looks similar to the previous one; you mock out the HTTP client and ensure it returns the expected data, and then you execute the Activity in the test environment. Then you retrieve the value and ensure it's what you expect.
Run the tests to see them pass:
bundle exec ruby -Ilib:test test/get_ip_activity_test.rb
bundle exec ruby -Ilib:test test/get_location_activity_test.rb
Finished tests in 0.000718s, 1392.7570 tests/s, 1392.7570 assertions/s.
1 tests, 1 assertions, 0 failures, 0 errors, 0 skips
Now that you have your tests passing, it's time to start a Workflow Execution and observe how Temporal handles failures.
Get notified when we launch new educational content
New courses, tutorials, and learning resources - straight to your inbox.