Add some unit tests

This commit is contained in:
Eugene Burmakin 2024-04-02 23:20:25 +02:00
parent 5544bcd5ff
commit 48962e87e8
7 changed files with 286 additions and 17 deletions

View file

@ -5,20 +5,16 @@ class Stat < ApplicationRecord
belongs_to :user
def timespan
DateTime.new(year, month).beginning_of_month..DateTime.new(year, month).end_of_month
end
def distance_by_day
timespan.to_a.map.with_index(1) do |day, index|
beginning_of_day = day.beginning_of_day.to_i
end_of_day = day.end_of_day.to_i
data = { day: index, distance: 0 }
# We have to filter by user as well
points = Point.where(timestamp: beginning_of_day..end_of_day)
data = { day: index, distance: 0 }
points.each_cons(2) do |point1, point2|
distance = Geocoder::Calculations.distance_between(
[point1.latitude, point1.longitude], [point2.latitude, point2.longitude]
@ -49,12 +45,18 @@ class Stat < ApplicationRecord
data = CountriesAndCities.new(points).call
{ countries: data.count, cities: data.sum { |country| country[:cities].count } }
{ countries: data.map { _1[:country] }.uniq.count, cities: data.sum { |country| country[:cities].count } }
end
def self.years
starting_year = pluck(:year).uniq.min || Time.current.year
starting_year = select(:year).min&.year || Time.current.year
(starting_year..Time.current.year).to_a.reverse
end
private
def timespan
DateTime.new(year, month).beginning_of_month..DateTime.new(year, month).end_of_month
end
end

View file

@ -1,6 +1,7 @@
FactoryBot.define do
factory :import do
user_id { "" }
user
name { 'APRIL_2013.json' }
source { 1 }
end
end

View file

@ -21,7 +21,7 @@ FactoryBot.define do
raw_data { "" }
tracker_id { "MyString" }
import_id { "" }
city { "MyString" }
country { "MyString" }
city { nil }
country { nil }
end
end

View file

@ -0,0 +1,61 @@
require 'rails_helper'
RSpec.describe ReverseGeocodingJob, type: :job do
describe '#perform' do
subject(:perform) { described_class.new.perform(point.id) }
let(:point) { create(:point) }
before do
allow(Geocoder).to receive(:search).and_return([double(city: 'City', country: 'Country')])
end
context 'when REVERSE_GEOCODING_ENABLED is false' do
before { stub_const('REVERSE_GEOCODING_ENABLED', false) }
it 'does not update point' do
expect { perform }.not_to change { point.reload.city }
end
it 'does not call Geocoder' do
perform
expect(Geocoder).not_to have_received(:search)
end
end
context 'when REVERSE_GEOCODING_ENABLED is true' do
before { stub_const('REVERSE_GEOCODING_ENABLED', true) }
it 'updates point with city and country' do
expect { perform }.to change { point.reload.city }.from(nil)
end
it 'calls Geocoder' do
perform
expect(Geocoder).to have_received(:search).with([point.latitude, point.longitude])
end
context 'when point has city and country' do
let(:point) { create(:point, city: 'City', country: 'Country') }
before do
allow(Geocoder).to receive(:search).and_return(
[double(city: 'Another city', country: 'Some country')]
)
end
it 'does not update point' do
expect { perform }.not_to change { point.reload.city }
end
it 'does not call Geocoder' do
perform
expect(Geocoder).not_to have_received(:search)
end
end
end
end
end

View file

@ -1,5 +1,20 @@
require 'rails_helper'
RSpec.describe StatCreatingJob, type: :job do
pending "add some examples to (or delete) #{__FILE__}"
describe '#perform' do
let(:user) { create(:user) }
subject { described_class.perform_now([user.id]) }
before do
allow(CreateStats).to receive(:new).and_call_original
allow_any_instance_of(CreateStats).to receive(:call)
end
it 'creates a stat' do
subject
expect(CreateStats).to have_received(:new).with([user.id])
end
end
end

View file

@ -1,6 +1,135 @@
require 'rails_helper'
RSpec.describe Stat, type: :model do
it { is_expected.to validate_presence_of(:year) }
it { is_expected.to validate_presence_of(:month) }
describe 'associations' do
it { is_expected.to belong_to(:user) }
it { is_expected.to validate_presence_of(:year) }
it { is_expected.to validate_presence_of(:month) }
end
describe 'methods' do
let(:year) { 2021 }
describe '.year_cities_and_countries' do
subject { described_class.year_cities_and_countries(year) }
before do
stub_const('MINIMUM_POINTS_IN_CITY', 1)
end
context 'when there are points' do
let!(:points) do
create_list(:point, 3, city: 'City', country: 'Country', timestamp: DateTime.new(year, 1))
create_list(:point, 2, city: 'Some City', country: 'Another country', timestamp: DateTime.new(year, 2))
end
it 'returns countries and cities' do
expect(subject).to eq(countries: 2, cities: 2)
end
end
context 'when there are no points' do
it 'returns countries and cities' do
expect(subject).to eq(countries: 0, cities: 0)
end
end
end
describe '.years' do
subject { described_class.years }
context 'when there are no stats' do
it 'returns years' do
expect(subject).to eq([Time.current.year])
end
end
context 'when there are stats' do
let(:user) { create(:user) }
let(:expected_years) { (year..Time.current.year).to_a.reverse }
before do
create(:stat, year: 2021, user: user)
create(:stat, year: 2020, user: user)
end
it 'returns years' do
expect(subject).to eq(expected_years)
end
end
end
describe '#distance_by_day' do
subject { stat.distance_by_day }
let(:user) { create(:user) }
let(:stat) { create(:stat, year: year, month: 1, user: user) }
let(:expected_distance) do
# 31 day of January
(1..31).map { |day| [day, 0] }
end
context 'when there are points' do
let!(:points) do
create(:point, latitude: 1, longitude: 1, timestamp: DateTime.new(year, 1, 1, 1))
create(:point, latitude: 2, longitude: 2, timestamp: DateTime.new(year, 1, 1, 2))
end
before { expected_distance[0][1] = 157.23 }
it 'returns distance by day' do
expect(subject).to eq(expected_distance)
end
end
context 'when there are no points' do
it 'returns distance by day' do
expect(subject).to eq(expected_distance)
end
end
end
describe '#timespan' do
subject { stat.send(:timespan) }
let(:stat) { build(:stat, year: year, month: 1) }
let(:expected_timespan) { DateTime.new(year, 1).beginning_of_month..DateTime.new(year, 1).end_of_month }
it 'returns timespan' do
expect(subject).to eq(expected_timespan)
end
end
describe '#self.year_distance' do
subject { described_class.year_distance(year) }
let(:user) { create(:user) }
let(:expected_distance) do
(1..12).map { |month| [Date::MONTHNAMES[month], 0] }
end
context 'when there are stats' do
let!(:stats) do
create(:stat, year: year, month: 1, distance: 100, user: user)
create(:stat, year: year, month: 2, distance: 200, user: user)
end
before do
expected_distance[0][1] = 100
expected_distance[1][1] = 200
end
it 'returns year distance' do
expect(subject).to eq(expected_distance)
end
end
context 'when there are no stats' do
it 'returns year distance' do
expect(subject).to eq(expected_distance)
end
end
end
end
end

View file

@ -1,7 +1,68 @@
require 'rails_helper'
RSpec.describe User, type: :model do
it { is_expected.to have_many(:imports).dependent(:destroy) }
it { is_expected.to have_many(:points).through(:imports) }
it { is_expected.to have_many(:stats) }
describe 'associations' do
it { is_expected.to have_many(:imports).dependent(:destroy) }
it { is_expected.to have_many(:points).through(:imports) }
it { is_expected.to have_many(:stats) }
end
describe 'methods' do
let(:user) { create(:user) }
xdescribe '#export_data' do
subject { user.export_data }
let(:import) { create(:import, user: user) }
let(:point) { create(:point, import: import) }
it 'returns json' do
expect(subject).to include(user.email)
expect(subject).to include('dawarich-export')
expect(subject).to include(point.attributes.except('raw_data', 'id', 'created_at', 'updated_at', 'country', 'city', 'import_id').to_json)
end
end
describe '#total_km' do
subject { user.total_km }
let!(:stat_1) { create(:stat, user: user, distance: 10) }
let!(:stat_2) { create(:stat, user: user, distance: 20) }
it 'returns sum of distances' do
expect(subject).to eq(30)
end
end
describe '#total_countries' do
subject { user.total_countries }
let!(:stat) { create(:stat, user: user, toponyms: [{ 'country' => 'Country' }]) }
it 'returns number of countries' do
expect(subject).to eq(1)
end
end
describe '#total_cities' do
subject { user.total_cities }
let!(:stat) { create(:stat, user: user, toponyms: [{ 'city' => 'City' }]) }
it 'returns number of cities' do
expect(subject).to eq(1)
end
end
describe '#total_reverse_geocoded' do
subject { user.total_reverse_geocoded }
let(:import) { create(:import, user: user) }
let!(:point) { create(:point, country: 'Country', city: 'City', import: import) }
it 'returns number of reverse geocoded points' do
expect(subject).to eq(1)
end
end
end
end