--
You received this message because you are subscribed to the Google Groups "rspec" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rspec+un...@googlegroups.com.
To post to this group, send email to rs...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/rspec/61ac9ade-1045-4211-80d3-441ef01ae7cb%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
To view this discussion on the web visit https://groups.google.com/d/msgid/rspec/3FF6FCF2018A482CBDC70C02BAFFB643%40jonrowe.co.uk.
To unsubscribe from this group and stop receiving emails from it, send an email to rspec+unsubscribe@googlegroups.com.
To post to this group, send email to rs...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/rspec/28f3f239-1515-437b-b011-82b2dd163502%40googlegroups.com.
To unsubscribe from this group and stop receiving emails from it, send an email to rspec+unsubscribe@googlegroups.com.
To post to this group, send email to rs...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/rspec/c297c4c9-5225-47d9-a6e2-80f461bd1226%40googlegroups.com.
RSpec.describe 'Authentication' do
subject { AuthenticationService.new }
let(:user_schema) { SchemaService.new }
context 'When creating a user that does not exists ' do
it 'response with status code 200 (success)' do
schema_name = SecureRandom.uuid.to_s
user_schema.create_schema(schema_name)
payload = JSON.parse(File.read('spec/acceptence/fixtures/feature.json'))
payload['schema_name'] = schema_name
response = subject.create_user(user: 'my_user', payload: payload)
expect(response.code).to eq 200
end
it 'creates a new user' do
schema_name = SecureRandom.uuid.to_s
user_schema.create_schema(schema_name)
payload = JSON.parse(File.read('spec/acceptence/fixtures/feature.json'))
payload['schema_name'] = schema_name
subject.create_user(user: 'my_user', payload: payload)
response = subject.get_user_by_category(category: payload['category'])
remote_entity = JSON.parse(response.body)
expect(payload.to_json).to eq(
remote_entity['list'][unique_value]
)
end
end
end
before(:all)
schema_name = SecureRandom.uuid.to_s
user_schema.create_schema(schema_name)
endlet(:schema_name) { SecureRandom.uuid.to_s }
before(:all)
user_schema.create_schema(schema_name)
endpayload = JSON.parse(File.read('spec/acceptence/fixtures/feature.json'))
payload['schema_name'] = schema_name
subject.create_user(user: 'my_user', payload: payload)
To view this discussion on the web visit https://groups.google.com/d/msgid/rspec/48d88387-8e71-49a5-b25a-850a79fe4181%40googlegroups.com.
before(:all) hooks require special care and we usually recommend you avoid them. Most RSpec tooling assumes a per-example lifecycle for resources (such as DB transactions, test doubles, and let memoization), and before(:all) hooks operate outside that lifecycle. If you’re not careful to manage the resources explicitly you’re likely to experience problems from using :all hooks. For this reason we don’t provide syntactic sugar for them (such as a let construct), but it’s pretty trivial to create your own construct if you want:
module BeforeAllConstructs
def set(name, &block)
attr_reader name
before(:context) { instance_variable_set("@#{name}", block.call }
end
end
RSpec.configure do |config|
config.extend BeforeAllConstructs
end
With this in place, you could use set in place of let to have a construct like let designed for :all/:context hooks.
That said, in your case, I wouldn’t recommend you take that route. It doesn’t seem like having two separate examples here provides you any clear benefit, and the fact you are considering using a before(:all) hook indicates you want to do some computation once, and then make multiple assertions about that. Instead, I’d recommend you combine the two examples, but then use :aggregate_failures so that you get a list of all failures (and not just the first one). Here’s how you could do that:
RSpec.describe 'Authentication' do
subject { AuthenticationService.new }
let(:user_schema) { SchemaService.new }
context 'When creating a user that does not exists ' do
it 'creates a new user', :aggregate_failures do
schema_name = SecureRandom.uuid.to_s
user_schema.create_schema(schema_name)
payload = JSON.parse(File.read('spec/acceptence/fixtures/feature.json'))
payload['schema_name'] = schema_name
response = subject.create_user(user: 'my_user', payload: payload)
expect(response.code).to eq 200
response = subject.get_user_by_category(category: payload['category'])
remote_entity = JSON.parse(response.body)
expect(payload.to_json).to eq(
remote_entity['list'][unique_value]
)
end
end
end
HTH,
Myron
To unsubscribe from this group and stop receiving emails from it, send an email to rspec+unsubscribe@googlegroups.com.
To post to this group, send email to rs...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/rspec/3ae74ab4-f4fd-4f17-b87f-4256656b57d4%40googlegroups.com.
let(schema_name) { SecureRandom.uuid.to }
before
user_schema.create_schema(schema_name)
end
it 'my test' do
puts schema_name
end
payload = JSON.parse(File.read('spec/acceptence/fixtures/feature.json'))
payload['schema_name'] = config(:default_schema_name)This however makes the test less clear because not all information is being exposed when you read just the spec file. I would like to do it the 'proper' way - as I can probably talk with the other teams in the future - makes those test better align with the standards.I don’t have sufficient information to tell you what I’d do in this situation, but here are some general principles to help you think through the tradeoffs here.
before(:context) hook caries a high maintenance cost since it has so many caveats compared to a typical before(:example) hook.:aggregate_failures for all my integration and acceptance tests.before(:context) hook. Instead, I’d probably do something like this:# spec/spec_helper.rb
module UserSchemaCache
def self.schema
@schema ||= SecureRandom.uuid.tap do |schema_name|
SchemaService.new.create_schema(schema_name)
end
end
end
RSpec.configure do |config|
config.when_first_matching_example_defined(:needs_schema) do
UserSchemaCache.schema
end
end
# some_spec.rb
RSpec.describe 'Authentication', :needs_schema do
# ...
end
That allows you to use the same user schema among all your end-to-end examples, incurring the cost of creating it only once. The when_first_matching_example_defined hook is only invoked if there’s an example matching :needs_schema, so there’s no cost when running your other specs.
HTH,
Myron
To unsubscribe from this group and stop receiving emails from it, send an email to rspec+unsubscribe@googlegroups.com.
To post to this group, send email to rs...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/rspec/adfd947f-875e-47cf-91e5-a95264f7aedc%40googlegroups.com.
Well, I will time it. So a rule of a thumb would be anything below 500ms can go inside the test iself?
The rule of thumb for what’s too long depends on what you can tolerate, how much value the tests provide, etc.
Also, you mentioned your following ‘one behaviour per example’. If I’m correct,
itis a behaviour per example.
The it method certainly lends itself to describing a single behavior, but there’s nothing stopping you from describing what would normally be considered more than one behavior: e.g. it "persists the expense, returns it when queried with the expense date, and includes it in the date's expense total".
It’s all a matter of trade offs, what you’re trying to achieve, how fast you need your test suite to run, etc.
So I’m assuming that in integration tests/acceptance tests you always have on it block per context with multiple assertions in it?
Nope. Integration and acceptance tests will still have multiple examples in an example group. All I’m saying is that in an integration or acceptance test, I’m keenly aware of the cost of repeating slow setup many times, and so I don’t necessarily strive for “one behavior per example”. I compare the costs of the tests to the value I'm getting out of them, and look for ways to cut the cost of the tests (e.g. by cutting down the time it takes to run them). For example, I’ve worked on JSON APIs that are basically read-only APIs, but do tons of data processing to prepare the data set to be queried. In this kind of situation, my end-to-end tests aren’t limited to one JSON endpoint per test, because my test time is dominated by how long it takes to prepare the dataset. If the data prep time is 10 seconds, and hitting a JSON endpoint takes 100ms, it makes a big difference to group lots of related JSON endpoints into a single end-to-end test that spends 10 seconds building the dataset once, and then hits lots of JSON endpoints to demonstrate they work in an end-to-end manner, without paying a 10 second per endpoint cost.
Schema creation however is not enough, as I need the name of the scehma. Will the above let me use “UserSchemCache.schema” to get the schema name?
You can cache or assign the schema name in the when_first_matching_example_defined hook as well. The UserSchemaCache module is just a normal ruby module, with nothing RSpec-specific in it, so do whatever you need to do there to compute, store, and expose whatever state you need.
To unsubscribe from this group and stop receiving emails from it, send an email to rspec+unsubscribe@googlegroups.com.
To post to this group, send email to rs...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/rspec/0f5083dc-5a77-44ee-af4f-44a34d8a4e56%40googlegroups.com.