I have a test case like this.
subject(:report) { @report.data }
it { expect(report[0][:id]).to eq(@c1.id) }
it { expect(report[1][:id]).to eq(@c2.id) }
it { expect(report[2][:id]).to eq(@c3.id) }
it { expect(report[0][:title]).to eq("Announcement3") }
it { expect(report[1][:title]).to eq("Announcement2") }
it { expect(report[2][:title]).to eq("Announcement1") }
I feel this is not really an efficient way.
Is there any other way to make it efficient ? So that it looks like one line condition.
Always test behavior, not composition. What you ought to be testing here is the behavior that given some set of fixed inputs, a report will generate the same fixed output every single time. You aren't doing that; you're introspecting individual report elements, which is about composition.
Instead, consider using fixtures or FactoryGirl (or even just a setup block) to define fixed inputs, and then check that:
it 'creates valid report data' do
expect(@report.data).to eq @sample.data
end
If each element of your report is coming from a different method, you ought to be testing the behavior of each of those methods separately, rather than decomposing the final report. That is another way to make your test clearer and more meaningful, and addresses the "unit" in unit testing.