loading...

re: How to test that you are creating a record without using the database VIEW POST

FULL DISCUSSION
 

Great! I've thought this several years ago but no solution.

I tried simple case, it really works.

But if I want to test a blog's title validation of presence, how could I do it. The DummyStore cannot validate, any suggestion?

Thanks your share.

  it "should not creates a record" do
    attrs = { title: "", body: "Super Product" }

    # This is the code that expects "store.create" not to be called
    expect(store).not_to receive(:create)

    BlogList.add_blog(attrs, store)
  end  
 

Start by trying to express in your tests what the client will need...

For example if you need validation... Maybe at the client you will need something to know if the action was successful or not, and if it was not successful you will need to show why it was not successful...

What I do in this cases is something like this...

describe "without title..." do
  it "does not returns success" do
    attrs = { title: nil, description: "Super post..." }
    status = add_blog(attrs, store)
    expect(status).not_to be_success
  end

  it "does not creates the record" do
    attrs = { title: nil, description: "Super post..." }
    expect(store).not_to receive(:create)
    add_blog(attrs, store)
  end

  it "returns an error" do
    attrs = { title: nil, description: "Super post..." }
    status = add_blog(attrs, store)
    expect(status.form.errors[:title]).to eq ["can't be blank"]
  end
end

About where you should do the validation, is up to you and your other
use cases... Why don't you try to implement something to make this pass?

As a hint... You can use ActiveModel, but try not to delegate this
responsibility to the store.

I have this post with a little template that I use, that maybe can help you...
bhserna.com/2018/a-little-template...

And this is a gist with a similar example that I did sometime ago...
gist.github.com/bhserna/925cba5b8b...

=)

 
class Blog 
  validates :title, presence: true
end

# no validation 
Blog.save(attrs)

# has validation
blog = Blog.new
blog.save(attrs)

Instance method save trigger validation, but class method save not trigger validation. Is this true or I do something wrong? I think it should trigger validation too.

I've got the answer. The validation works but seems not easy to test.

!@blog.id.nil? #this works, any better code?

I can plan two stages test. First stage don't test validation. In second integration test I can use model test to do validation test. Do you agree with me? :)

I would test the validation part, just as I said in the comment... This
is because, most of the time I don't put validation code in the Rails
models.

I would put the behavior in a kind of form object, in fact, you could use
ActiveModel if you want...

Two possible solutions could be...

Without ActiveModel...

module Blog
  def self.add_post(attrs, store)
    form = Form.new(attrs)

    if form.title.nil?
      form.add_error!(:title, "can't be blank")
      ErrorStatus.new(form)
    else
      store.create(form.to_h)
      SuccessStatus
    end
  end

  class Form
    attr_reader :title, :body, :errors

    def initialize(params = {})
      @title = params["title"]
      @body = params["body"]
      @errors = {}
    end

    def to_h
      { title: title, body: body }
    end

    def add_error!(field, error)
      errors[field] ||= []
      errors[field] << error
    end
  end

  class ErrorStatus
    attr_reader :form

    def initialize(form)
      @form = form
    end

    def success?
      false
    end
  end

  class SuccessStatus
    def self.success?
      true
    end
  end
end

With ActiveModel...

module Blog
  def self.add_post(attrs, store)
    form = Form.new(attrs)

    if form.valid?
      store.create(form.to_h)
      SuccessStatus
    else
      ErrorStatus.new(form)
    end
  end

  class Form
    include ActiveModel::Model
    attr_accessor :title, :body
    validates_presence_of :title

    def to_h
      { title: title, body: body }
    end
  end

  # ...
end

Looks nice, thanks.

Then you don't write rails AR validation, is this true?

Is really rare... but I do use ActiveModel for form objects very often

Code of Conduct Report abuse