Arranging test environment

A test basically consists of the the 3 steps:

1.) Arrange 2.) Act 3.) Assert

In the first step (Arrange) the necessary testing environment is made up for running the test. The effort depends on the test.
If test complexity is unreasonably high and it takes much effort to make up the objects, the problem is more the implementation than the test itself. Then it is rewarding to think about, why the complexity is that high. A test, that is hard to write, is a code smell for a bad implementation.
In general only objects, which are significant for running the test, should be created. Ideally this is just one object: the object under test.

Factories for test object

If it takes some effort to generate test objects, it makes sense to use factories.
This makes maintaining test objects easy. There is just one location: the factory. In Ruby land the Gem FactoryGirl is quite established for that task.

FactoryGirl.define do
  factory :person do
    name 'Alice'
    birthday { Date.new 1978, 3, 17 }
    association :address, strategy: :build
  end
end

The factory in action:

# Test with RSpec
describe Person do
  subject { build(:person) }

  it { is_expected.to be_valid }
end

Test objects with predictable data

Test objects should have predictable data. Then and only then the test evidence has a value and is reproducible.
Test objects with random data are more a sign of uncertainty, if all test cases are completely covered.
That is why gems like Faker, generating random data should not be used in the test environment:

FactoryGirl.define do
  factory :person do
    # bad
    name Faker::Name.first_name
  end
end

If setting the data explicitly in the test itself improves the test comprehension, then it should be done. Even if it was already defined in the factory:

describe Person do
  subject { build(:person) }

  describe '#adult?' do
    context 'when older than 19 years' do
      it 'returns true' do
        subject.birthday = 19.years.ago
        expect(subject.adult?).to be true
      end
    end
  end
end

Modularize test objects

The more test cases, the more likely test objects of the same type have to have different data. Creating a factory for each test case is awkward.
FactoryGirl hast traits for that. A trait is the possibility to set different data, but adopt all other:

FactoryGirl.define do
  factory :person do
    name 'Alice'

    trait :with_jobs do
      jobs { build_list(:job, 1) }
    end
  end
end

and then:

build(:person).jobs
# => #<ActiveRecord::Associations::CollectionProxy []>

or:

build(:person, :with_jobs).jobs
# => #<ActiveRecord::Associations::CollectionProxy [#<Job id: nil, name: "Egineer">]>

Avoid touching the database

In some tests database accesses are necessary, but they slow down the test suite. Doing TDD (Test Driven Development), slow tests are cumbersome. Needless database accesses should be avoided. Once again, if it is costly to test a case, then the implementation probably is not optimal.
If there really is the need for persistence, then as late as possible in the test cycle.
So neither in the factory:

# Schlecht
factory :person do
  association :address
end
build(:person).address.new_record? # => false

# Gut
factory :person do
  association :address, strategy: :build
end
build(:person).address.new_record? # => true

and also not in the test hooks:

# Schlecht
describe Person do
  subject { create(:person) }
end

# Gut
describe Person do
  subject { build(:person) }
end

but as late as possible:

describe Person do
  subject { build(:person) }

  describe '.adult' do
    it 'returns adult people' do
      subject.birthday = 18.years.ago
      subject.save
      create(:person, birthday: 17.years.ago)
      expect(Person.adult).to eq([subject])
    end
  end
end

That is how the test performance can be improved. Besides side effects to other tests can be avoided, because the persisted test objects are reasonable.

Stubbing access to external systems

In the tests, accesses to external systems should not be executed for several reasons. They are slow in any case. And they can be problematic, because the external system is productive. Besides the access does not add any value to the test in most cases. The goal is not to test data, but behaviour.
It makes sense to build mocks as external systems or stub the accessing methods out:

describe ExternalArticleCollector do
  subject { described_class.new }

  describe '#fetch' do
    before do
      WebMock.stub_request(:get, 'http://www.chrisrolle.com/blog')
                        .to_return(body: '{ "articles": [] }')
    end

    it 'returns JSON' do
      expect(subject.fetch).to be_kind_of(JSON)
    end
end