I have this intent.
Context: asset
Query: When will the #asset fail?
Entity #asset has synonyms "unit, equipment, machine"
Now when I query "when will the asset fail? or when will the unit fail?"
It works.
But when I say "when will it fail?"
It does not work.
Is there a way I can make the entity #asset optional?
There are two ways to deal with that.
When you want an asset, than you set asset to required.
Then you use a feature called slotfilling. You set a prompt like:
What asset do you mean?
User says:
When will it fail
When will the unit fail <-- mark the unit as asset
In the Action segment you may set asset to required and set a prompt.
If it is set. API.ai tries to "fill the slot" by showing the user the prompt:
(Example: What asset do you mean?)
If required isn't set:
When will it fail will be accepted and the asset field is empty. In this case your backend has to handle it.
Either with a default value or an error message.
Of course it is better for the experience of the user, if he doesn't get a: I don't know what you mean response ;-)
Related
It said here https://www.relishapp.com/rspec/rspec-core/v/3-5/docs/helper-methods/let-and-let what variable defined by let is changing across examples.
I've made the same simple test as in the docs but with the AR model:
RSpec.describe Contact, type: :model do
let(:contact) { FactoryGirl.create(:contact) }
it "cached in the same example" do
a = contact
b = contact
expect(a).to eq(b)
expect(Contact.count).to eq(1)
end
it "not cached across examples" do
a = contact
expect(Contact.count).to eq(2)
end
end
First example passed, but second failed (expected 2, got 1). So contacts table is empty again before second example, inspite of docs.
I was using let and was sure it have the same value in each it block, and my test prove it. So suppose I misunderstand docs. Please explain.
P.S. I use DatabaseCleaner
P.P.S I turn it off. Nothing changed.
EDIT
I turned off DatabaseCleaner and transational fixtures and test pass.
As I can understand (new to programming), let is evaluated once for each it block. If I have three examples each calling on contact variable, my test db will grow to three records at the end (I've tested and so it does).
And for right test behevior I should use DatabaseCleaner.
P.S. I use DatabaseCleaner
That's why your database is empty in the second example. Has nothing to do with let.
The behaviour you have shown is the correct behaviour. No example should be dependant on another example in setting up the correct environment! If you did rely on caching then you are just asking for trouble later down the line.
The example in that document is just trying to prove a point about caching using global variables - it's a completely different scenario to unit testing a Rails application - it is not good practice to be reliant on previous examples to having set something up.
Lets, for example, assume you then write 10 other tests that follow on from this, all of which rely on the fact that the previous examples have created objects. Then at some point in the future you delete one of those examples ... BOOM! every test after that will suddenly fail.
Each test should be able to be tested in isolation from any other test!
I have the following ActiveRecord model class method:
def self.find_by_shortlink(shortlink)
find_by!(shortlink: shortlink)
end
When I run Mutant against this method, I'm told there were 17 mutations and 16 are still "alive" after the test has run.
Here's one of the "live" mutations:
-----------------------
evil:Message.find_by_shortlink:/home/peter/projects/kaboom/app/models/message.rb:29:3f9f2
## -1,4 +1,4 ##
def self.find_by_shortlink(shortlink)
- find_by!(shortlink: shortlink)
+ find_by!(shortlink: self)
end
If I manually make this same change, my tests fail - as expected.
So my question is: how do I write a unit test that "kills" this mutation?
Disclaimer, mutant author speaking.
Mini cheat sheet for such situations:
Make sure your specs are green right now.
Change the code as the diff shows
Try to observe an unwanted behavior change.
Impossible?
(likely) Take the mutation as better code.
(unlikely) Report a bug to mutant
Found a behavior change: Encode it as a test, or change a test to cover that behavior.
Rerun mutant to verify the death of the mutation.
Make sure mutant actually lists the tests you added as used for that mutation. If not restructure the tests to cover the subject of the mutation in the selected tests.
Now to your case: If you apply the mutation to your code. The argument gets ignored and essentially hardcoded (the value for key :shortlink used in your finder does not change depending on argument shortlink). So the only thing you need to do in your test is adding a case where the argument shortlink matters to the expectation you place in the test.
If passing self as value for the :shortlink finder has the same effect as passing in the current argument you test, try to use a different argument. Coercion of values in finders can be tricky in AR, there is the chance your model coerces to the same value you are testing as argument.
I am creating a new record in my tests... during the creation of the record, the application calls another class to notify a user about the creation of the record..
A contrived example might be
user = User.make!
expect_any_instance_of(Notifier).to receive(:tell_user).with(user.id, new_message_id)
Message.create(author: User.make!, recepient: user, message: 'this is a test')
Now obviously I don't know the id of the message that will be created.
So I'm wondering if anyone knows how I'd construct the with part of the expect to not care about the value in the second parameter, but to care about the value in the first parameter.
Thanks for any help.
I think what you are looking for is the kind_of method
user = User.make!
expect_any_instance_of(Notifier).to receive(:tell_user).with(user.id, kind_of(Numeric))
Message.create(author: User.make!, recepient: user, message: 'this is a test')
You can also use instance_of(Fixnum) if you want to be more specific
I have the following code to test file uploading:
test 'when a user adds an attachment to an existing candidate, the attachment shows up on the candidates page' do
user = login_user
opportunity = opportunities(:with_candidates)
candidate = candidates(:first)
upload = fixture_file_upload(ActionController::TestCase.fixture_path + 'files/file_upload_support_image.jpeg', 'image/jpeg')
attributes = { attachments: [upload] }
user.put opportunity_candidate_path(opportunity, candidate, request: attributes)
user.follow_redirect!
assert_match /#{upload.original_filename}/, fixer.response.body, 'The filename of the attachment should appear on the opportunity candidates page'
end
The test fails because the file does not get attached.
The code works when run through the browser – it turns out I had written the assert incorrectly and was getting a false pass. Now the assert is correct, the test fails.
When debugging, I find that the upload variable in the test is something like #<Rack::Test::UploadedFile:0x007f85ca141c50>. However, when I debug the controller, the value in the params hash is "#<Rack::Test::UploadedFile:0x007f85ca141c50>".
Note the quote marks. Rails has turned the file upload into a string!
Since there’s none of my code between the test and the controller, and this works when the app is run in the browser, I guess something may be wrong with how I am constructing the params hash or the tempfile itself in the test.
Any ideas what I am doing wrong?
Okay, turns out I was doing something incorrectly in the test. However, this error does not manifest if you are passing the most common types of parameter, so it can be a little tricky to spot!
The line
user.put opportunity_candidate_path(opportunity, candidate, request: attributes)
Should be
user.put opportunity_candidate_path(opportunity, candidate), request: attributes
Note the moved parenthesis. D’oh!
The reason this may not be easy to spot is that unknown keys in the ..._path method are still passed as parameters. However, they are parsed having been encoded into the URL querystring, like a GET request.
For the common cases of passing text values and integer foreign keys in as params, this mangling doesn’t prevent anything working, it’s only for more complex objects that it becomes an issue.
What's the best practices way to test that a model is valid in rails?
For example, if I have a User model that validates the uniqueness of an email_address property, how do I check that posting the form returned an error (or better yet, specifically returned an error for that field).
I feel like this should be something obvious, but as I'm quickly finding out, I still don't quite have the vocabulary required to effectively google ruby questions.
The easiest way would probably be:
class UserEmailAddressDuplicateTest < ActiveSupport::TestCase
def setup
#email = "test#example.org"
#user1, #user2 = User.create(:email => #email), User.new(:email => #email)
end
def test_user_should_not_be_valid_given_duplicate_email_addresses
assert !#user2.valid?
end
def test_user_should_produce_error_for_duplicate_email_address
# Test for the default error message.
assert_equal "has already been taken", #user2.errors.on(:email)
end
end
Of course it's possible that you don't want to create a separate test case for this behaviour, in which case you could duplicate the logic in the setup method and include it in both tests (or put it in a private method).
Alternatively you could store the first (reference) user in a fixture such as fixtures/users.yml, and simply instantiate a new user with a duplicate address in each test.
Refactor as you see fit!
http://thoughtbot.com/projects/shoulda/
Shoulda includes macros for testing things like validators along with many other things. Worth checking out for TDD.
errors.on is what you want
http://api.rubyonrails.org/classes/ActiveRecord/Errors.html#M002496
#obj.errors.on(:email) will return nil if field is valid, and the error messages either in a String or Array of Strings if there are one or more errors.
Testing the model via unit tests is, of course, step one. However, that doesn't necessarily guarantee that the user will get the feedback they need.
Section 4 of the Rails Guide on Testing has a lot of good information on functional testing (i.e. testing controllers and views). You have a couple of basic options here: check that the flash has a message in it about the error, or use assert_select to find the actual HTML elements that should have been generated in case of an error. The latter is really the only way to test that the user will actually get the message.