How to mock aws-sdk gem?
There are a lot of ways to mock requests in the AWS SDK for Ruby. Trevor Rowe recently posted an article on using the SDK's native support for object stubbing, which does not require any external dependencies like Webmock. You can also use tools like VCR (link will send you to another blog post) to build cacheable integration tests; this way you can test against the live service when you want accuracy and avoid hitting network when you want speed.
Regarding the get request on latest/meta-data/iam/security-credentials/
, this happens because the SDK is trying to look up credentials, and, if none are provided, it will check if you are running on an EC2 instance as a last resort, causing the SDK to make an extra HTTP request. You can avoid this check by simply providing bogus static credentials, though if you are using something like VCR, you will want to provide valid credentials for the first run. You can read about how to provide static credentials in another blog post that Trevor wrote on credential management (this should also be in the developer guide and SDK documentation).
How to mock aws-sdk gem?
There are a lot of ways to mock requests in the AWS SDK for Ruby. Trevor Rowe recently posted an article on using the SDK's native support for object stubbing, which does not require any external dependencies like Webmock. You can also use tools like VCR (link will send you to another blog post) to build cacheable integration tests; this way you can test against the live service when you want accuracy and avoid hitting network when you want speed.
Regarding the get request on latest/meta-data/iam/security-credentials/
, this happens because the SDK is trying to look up credentials, and, if none are provided, it will check if you are running on an EC2 instance as a last resort, causing the SDK to make an extra HTTP request. You can avoid this check by simply providing bogus static credentials, though if you are using something like VCR, you will want to provide valid credentials for the first run. You can read about how to provide static credentials in another blog post that Trevor wrote on credential management (this should also be in the developer guide and SDK documentation).
How do I mock AWS SDK (v2) with rspec?
I had a hard time finding examples mocking AWS resources. I spent a few days figuring it out and wanted to share my results on Stack Overflow for posterity. I used rspec-mocks (doubles & verifying doubles). Here's an example with the communicator.rb
example in the question.
communicator_spec.rb:
RSpec.describe Communicator do
describe "#consume_messages" do
it "can use rspec doubles & verifying doubles to mock AWS SDK calls" do
sqs_client = instance_double(Aws::SQS::Client)
allow(Aws::SQS::Client).to receive(:new).and_return(sqs_client)
SQSResponse = Struct.new(:messages)
SQSMessage = Struct.new(:body, :receipt_handle)
response = SQSResponse.new([SQSMessage.new(File.read('data/expected_body.json'), "receipt_handle")])
empty_response = SQSResponse.new([])
allow(sqs_client).to receive(:receive_message).
and_return(response, empty_response)
allow(sqs_client).to receive(:delete_message).and_return(nil)
Communicator.new.consume_messages
end
end
end
How to Stub Responses with ruby Aws::Lambda::Client SDK
By following the code of stub_responses
, it brings you to convert_stub
. There seems to be three viable options to mock the responses with: Proc
, Hash
and the else
statement.
def convert_stub(operation_name, stub)
case stub
when Proc then stub
when Exception, Class then { error: stub }
when String then service_error_stub(stub)
when Hash then http_response_stub(operation_name, stub)
else { data: stub }
end
end
source
In the mocking examples below, I have my AWS client setup as such.
aws_credentials = {
region: 'us-east-1',
access_key_id: Rails.application.secrets.aws_key,
secret_access_key: Rails.application.secrets.aws_secret,
stub_responses: Rails.env.test?
}
LAMBDA_CLIENT = Aws::Lambda::Client.new(aws_credentials)
Mocking Aws::Lambda::Types::InvocationResponse
The else
statement allows you to essentially return the same object back. So the best way to mock the response, is to utilize the same class that is being used outside of the test environment. Aws::Lambda::Types::InvocationResponse
context do
before do
LAMBDA_CLIENT.stub_responses(
:invoke,
Aws::Lambda::Types::InvocationResponse.new(
executed_version: "$LATEST",
function_error: nil,
log_result: nil,
payload: StringIO.new("hello".to_json),
status_code: 200
)
)
end
it { ... }
end
Mocking the HTTP Response
Following the logic of using a Hash
, we need to peak into what http_response_stub
does.
def http_response_stub(operation_name, data)
if Hash === data && data.keys.sort == [:body, :headers, :status_code]
{ http: hash_to_http_resp(data) }
else
{ http: data_to_http_resp(operation_name, data) }
end
end
source
Evidently they are looking for a Hash
with the following keys [:body, :headers, :status_code]
context do
before do
LAMBDA_CLIENT.stub_responses(
:invoke,
{
body: {testing: true}.to_json,
headers: {},
status_code: 200
}
)
end
it { ... }
end
What gem should I use to work with AWS
You may also want to checkout rightaws though unfortunately it doesn't have support for sns either. It was one of the first libraries available and provides support for most of the functionalities. However, fog is releasing new versions more often and is catching up quickly and is a bit more high level. The aws_sdk was only released recently and the main reason to go with it is that it comes from Amazon itself and will likely become the standard. This is why we included it in rubystack. We expect that people will provide higher level libraries that will build on top of it.
How to test AWS S3 get object method ?
You don't need to (and you shouldn't even try) to test #get_object
. That is not implemented by your code and you should assume it has been tested and it works. As for you method #import_from_s3
, you have two options. You either don't test it since it is just a thin wrapper around #get_object
; or you can make assertions/expectations on its return value.
Related Topics
Rails Pass Params/Arguments to Activerecord Callback Function
Rails Activerecord Query Date Range
Ruby on Rails User Registration Using Rest API Call and Devise
Best Way to Work with Large Amounts of CSV Data Quickly
Solving the Travelling Salesman Problem in Ruby (50+ Locations)
Pretty Print to a File in Ruby
Rails 3 - Best Way to Handle Nested Resource Queries in Your Controllers
Whenever Gem: I Set :Output But the Logfile Doesn't Show Up Where I'D Expect It To
Running Parallel Selenium Tests with Capybara
List Dynamic Attributes in a Mongoid Model
Safe Navigation Equivalent to Rails Try for Hashes
How to Set the Httponly Flag on a Cookie in Ruby on Rails
Reversing the Order of an Array in Ruby
Parsing JSON Without Quoted Keys
What Is the Point of Object#Presence in Rails
Attempting to Install Libv8, "Failed to Build Gem Native Extension"