The Faker gem generates short, nonsense strings instead of what is described. For example, Faker::Job.title generates "et". If I have a feature test that expects not to find a Faker-generated string on the page, chances are it's going to fail if the string is "et". Surely this is unexpected behaviour, as nobody in the world has the job title "et".
This is my code, the most recent time I checked it the title was as expected, but the role and category were not:
# frozen_string_literal: true
shared_context 'with signatory attributes' do
let(:first_name) { Faker::Name.first_name }
let(:last_name) { Faker::Name.last_name }
let(:email) { Faker::Internet.email }
let(:title) { Faker::Job.title }
let(:mobile) { Faker::Number.number(10) }
let(:employee_num) { Faker::Number.number(10) }
let(:role) { Faker::Job.title }
let(:category) { Faker::Job.title }
end
Looks like Faker isn’t set up to make realistic job titles. But it’s easy to make your own random job titles. I would just sample your own custom array, like this:
let(:title) { %w[Admin Manager Engineer].sample }
You can use regex matcher with word boundaries instead of the short string only, but it is still not bullet-proof.
let(:first_name) { /\b#{Faker::Name.first_name}\b/ }
But maybe it is better to stub the attribute on model itself and raise an Error if it is called.
It seems like it pulls strings from its Lorem Ipsum String Set for some reason. Do you mind sharing your code?
Related
In the effort to make more readable my test suite, I'm introducing spies in my specs but I'm not sure how to deal with class methods. Is it possible to "spy a class"?
Let's say I have the following sample code
def publish(post)
Publisher.call(post)
post.save
end
And the correspondent spec
it 'delegates the publishing to Publisher' do
let(:blog) { ... }
let(:post) { ... }
expect(Publisher).to receive(:call).with(post).and_call_original
blog.publish(post)
end
Is it possible to rewrite the spec using a spy?
Thanks
You can use spies on partial doubles via allow plus expect:
it 'delegates the publishing to Publisher' do
let(:blog) { ... }
let(:post) { ... }
allow(Publisher).to receive(:call)
blog.publish(post)
expect(Publisher).to have_received(:call).with(post)
end
i am a beginner in grails and i have the following problem. Please help.
package racetrack
class Users {
String userName
String password
static constraints = {
userName(nullable:false, maxSize:20)
password(password:true, minSize: 8,
validator: {
return (it.matches("(.*[\\d])"))?true: ['noNumber']
return (it.matches("(.*[\\W])"))?true: ['noSpecialCh']
return (it.matches("(.*[a-z])"))?true: ['noLower']
return (it.matches("(.*[A-Z])"))?true: ['noUpper']
}
)
}
}
I created the above domain and in message.properties, i added the following:
users.password.validator.noNumber=should contain at least one number
users.password.validator.noLower=should contain at least one lower case letter as well
users.password.validator.noUpper=should contain number as well
users.password.validator.noSpecialCh=should contain number as well
however, i am not given required messages when tried with faulty values. Suppose, if i give no number in the password "should contain at least one number" message was expected but i only get does not match custom validation message.
The core problem is that Groovy, unlike Java, allows multiple return statements. If you converted that to Java it wouldn't compile.
Groovy allows multiple return statements, but obviously only considers the first, so with your code you have one check, not four, essentially
(it.matches("(.*[\\d])")) ? true : ['noNumber']
It should be something like this:
if (!it.matches("(.*[\\d])")) {
return ['noNumber']
}
if (!it.matches("(.*[\\W])")) {
return ['noSpecialCh']
}
if (!it.matches("(.*[a-z])")) {
return ['noLower']
}
if (!it.matches("(.*[A-Z])")) {
return ['noUpper']
}
except that all of the regexes are broken, but that's a separate issue.
I am writing a unit test for one of my service objects. In this particular case, I needed to use transactions to ensure data integrity. Thus, I have a simple code like so:
class CreateUser
def save
user_klass.db.transaction do
user = user_klass.create(name: name, email: email)
another_model_klass.find_or_create(user_id: user.id, foo: 'foo')
end
end
end
I am using Sequel as my ORM. However, the important point of this question is actually how to test this code. I have been successfully using mocks and stubs but this is the first time I have to stub out something with a block involved.
At first I have a naive spec like so:
describe CreateUser do
describe "#save" do
let(:user) { instance_double("User", id: 1) }
let(:user_klass) { double("Class:User", create: user) }
let(:another_model_klass) { double("Class:AnotherModel") }
let(:name) { 'Test User' }
let(:email) { 'test#test.com' }
let(:foo) { 'foo' }
let(:params) { { name: name, email: email, foo: foo } }
let!(:form) { CreateUser.new(params, user_klass, another_model_klass) }
before do
allow(another_model_klass).to receive(:find_or_create)
end
it "sends create message to the user_klass" do
expect(user_klass).to receive(:create).with({ name: name, email: email}).and_return(user)
form.save
end
it "sends find_or_create message to another_model_klass" do
expect(another_model_klass).to receive(:find_or_create).with(user_id: user.id, foo: foo)
form.save
end
end
end
This gives out an error:
Double "Class:User" received unexpected message :db with (no args)
But if I add the following:
allow(user_klass).to receive_message_chain(:db, :transaction)
It would stub out the contents of the transaction block and it would still fail.
How do set expectations on my spec where:
expect transaction to be used
expect the create message to be sent to user_klass
expect the find_or_create message to another_model_klass
You can do this:
let(:db) { double("DB") }
let(:user_klass) { double("Class:User", create: user, db: db) }
# ...
before do
allow(db).to receive(:transaction).and_yield
# ...
end
That said: you can do that, but I recommend you don't. In fact, I recommend you don't mock the Sequel API at all. I can speak from experience that down the road of mocking APIs you don't own lies brittle, low-value tests and lots of pain. The general approach that I (and many others) recommend is to wrap the API you don't own with your own API that you do own. Then you can integration test your wrapper (without doing mocking or stubbing) and mock or stub your simpler, domain-specific API in all the other places that rely on that functionality.
On a side note, if you're using RSpec 3, I highly recommend you switch your test doubles to verifying doubles as they provide some really nice guarantees that normal doubles don't provide.
Take a look at spies https://github.com/rspec/rspec-mocks#test-spies, you might be able to drop them in your doubles. :-)
I'm creating a factory for an account object and I'm setting the name like this:
name { "#{Faker::Hacker.ingverb} #{Faker::Hacker.adjective} #{Faker::Hacker.noun}" }
Is there a way to use a block to change the execution context to eliminate the redundant Faker::Hacker calls? I'd like to end up with something like this:
name { Faker::Hacker { "#{ingverb} #{adjective} #{noun}" } }
Thanks!
It looks like you are sending methods to a class/module, so your example may be simply rewritten with use of Module#class_eval method:
name { Faker::Hacker.class_eval { "#{ingverb} #{adjective} #{noun}" } }
would invoke methods in the block passed to class_eval on Faker::Hacker class.
Not a total solution according to your problem, but a lot less to type:
h = Faker::Hacker
name { "#{h.ingverb} #{h.adjective} #{h.noun}" }
EDIT: Please let me be clear, I'm asking how to do this in Grails using Spring Dependency Injection, and NOT Grails' metaclass functionality or new().
I have a grails service that is for analyzing log files. Inside the service I use the current time for lots of things. For unit testing I have several example log files that I parse with this service. These have times in them obviously.
I want my service, DURING UNIT TESTING to think that the current time is no more than a few hours after the last logging statement in my example log files.
So, I'm willing to this:
class MyService {
def currentDate = { -> new Date() }
def doSomeStuff() {
// need to know when is "right now"
Date now = currentDate()
}
}
So, what I want to be able to do is have currentDate injected or set to be some other HARDCODED time, like
currentDate = { -> new Date(1308619647140) }
Is there not a way to do this with some mockWhatever method inside my unit test? This kind of stuff was super easy with Google Guice, but I have no idea how to do it in Spring.
It's pretty frustrating that when I Google "grails dependency injection" all I find are examples of
class SomeController {
// wow look how amazing this is, it's injected automatically!!
// isn't spring incredible OMG!
def myService
}
It feels like all that's showing me is that I don't have to type new ...()
Where do I tell it that when environment equals test, then do this:
currentDate = { -> new Date(1308619647140) }
Am I just stuck setting this property manually in my test??
I would prefer not to have to create a "timeService" because this seems silly considering I just want 1 tiny change.
Groovy is a dynamic language, and as such it allows you to do almost what you're asking for:
class MyServiceTests extends GrailsUnitTestCase {
def testDoSomeStuff() {
def service = new MyService()
service.currentDate = { -> new Date(1308619647140) }
// assert something on service.doSomeStuff()
}
}
Keep in mind this only modifies the service instance, not the class. If you need to modify the class you'll need to work with the metaClass. Take a look at this post by mrhaki.
Another option would be to make the current date a parameter to doSomeStuff(). That way you wouldn't need to modify your service instance.
Thanks for the help guys. The best solution I could come up with for using Spring DI in this case was to do the following in
resources.groovy
These are the two solutions I found:
1: If I want the timeNowService to be swapped for testing purposes everywhere:
import grails.util.GrailsUtil
// Place your Spring DSL code here
beans = {
if (GrailsUtil.environment == 'test') {
println ">>> test env"
timeNowService(TimeNowMockService)
} else {
println ">>> not test env"
timeNowService(TimeNowService)
}
}
2: I could do this if I only want this change to apply to this particular service:
import grails.util.GrailsUtil
// Place your Spring DSL code here
beans = {
if (GrailsUtil.environment == 'test') {
println ">>> test env"
time1(TimeNowMockService)
} else {
println ">>> not test env"
time1(TimeNowService)
}
myService(MyService) {
diTest = 'hello 2'
timeNowService = ref('time1')
}
}
In either case I would use the service by calling
timeNowService.now().
The one strange, and very frustrating thing to me was that I could not do this:
import grails.util.GrailsUtil
// Place your Spring DSL code here
beans = {
if (GrailsUtil.environment == 'test') {
println ">>> test env"
myService(MyService) {
timeNow = { -> new Date(1308486447140) }
}
} else {
println ">>> not test env"
myService(MyService) {
timeNow = { -> new Date() }
}
}
}
In fact, when I tried that I also had a dummy value in there, like dummy = 'hello 2' and then a default value of dummy = 'hello' in the myService class itself. And when I did this 3rd example with the dummy value set in there as well, it silently failed to set, apparently b/c timeNow blew something up in private.
I would be interested to know if anyone could explain why this fails.
Thanks for the help guys and sorry to be impatient...
Since Groovy is dynamic, you could just take away your currentDate() method from your service and replace it by one that suits your need. You can do this at runtime during the setup of your test.
Prior to having an instance of MyService instantiated, have the following code executed:
MyService.metaClass.currentDate << {-> new Date(1308619647140) }
This way, you can have a consistent behavior across all your tests.
However, if you prefer, you can override the instance method by a closure that does the same trick.
Let me know how it goes.
Vincent Giguère