Reputation: 25542
Here is my module:
module ManagesVideoFiles
def self.included(klass)
klass.before_destroy :cleanup
klass.validates_presence_of :panda_id
end
def panda_video(being_destroyed = false)
@panda_video ||= panda_id ? Panda::Video.find(panda_id) : nil
rescue Panda::APIError => e
if e.message =~ /RecordNotFound/i
self.destroy unless being_destroyed
nil
end
end
def thumbnail_url(style = :web)
return read_attribute(:thumbnail_url) if read_attribute(:thumbnail_url).present?
return nil unless panda_video
return nil unless encoding = get_encoding
return nil if encoding.screenshots.blank?
secure_screenshot = encoding.screenshots.first.sub "http", "https"
self.update_attribute(:thumbnail_url, secure_screenshot)
return read_attribute(:thumbnail_url)
end
def mp4_url
return mp4_video_url unless mp4_video_url.blank?
return nil unless panda_video
return nil unless encoding = get_encoding
secure_url = encoding.try { |enc| enc.url.sub("http", "https") }
self.update_attribute(:mp4_video_url, secure_url)
end
def get_encoding
return nil unless panda_video
panda_video.encodings.detect { |vid| vid.encoding_progress == 100 && vid.status == "success" }
end
private
def cleanup
if respond_to?(:from_mobile_device?) && from_mobile_device?
bucket = AWS::S3.new.buckets[API["s3"][Rails.env]["bucket"] + "-videos"]
bucket.objects.delete(self.thumbnail_url.split("/").last, self.mp4_video_url.split("/").last)
elsif panda_video(true)
panda_video.delete
end
true
end
end
The method I am testing is #thumbnail_url... here are my tests:
require 'spec_helper'
describe ManagesVideoFiles do
let(:athlete) { create(:athlete) }
let(:video) { create(:video, athlete_id: athlete.id) }
describe "instance methods" do
describe "#thumbnail_url" do
context "when video has thumbail_url object property" do
it "should return thumbnail_url from database" do
url = "https://foo.com/image.ext"
video.thumbnail_url = url
video.save
video.thumbnail_url.should eq url
end
end
context "when panda_id is nil" do
it "should return nil" do
video.stub(:panda_id).with(nil)
video.stub(:panda_video).and_return nil
video.thumbnail_url.should be_nil
end
end
context "when panda can find video", focus: true do
it "should return encoding object with screenshots" do
video.stub(:panda_video).and_return double(encodings: [double(panda_encoding_object(100, :success))])
video.get_encoding.stub(:screenshots).and_return [ double({ url: "http://foo.com/image.ext" }) ]
video.thumbnail_url
video.thumbnail_url.should eq video.get_encoding.screenshots.first.url.sub "http", "https"
end
end
end
describe "#mp4_url" do
context "when encoding is available from panda" do
it "should set mp4 url to encoding from panda object" do
video.stub(:panda_video).and_return double(encodings: [double(panda_encoding_object(100, :success))])
video.mp4_url
video.mp4_video_url.should eq video.panda_video.encodings.first.url.sub("http", "https")
end
end
context "when encoding is not available from panda" do
it "should return nil" do
video.stub(:panda_id).with(nil)
video.stub(:panda_video).and_return nil
video.mp4_url.should be_nil
end
end
context "when encoding is available from panda but progress is less than 100" do
it "should return nil" do
video.stub(:panda_video).and_return double(encodings: [double(panda_encoding_object(50, :success))])
video.mp4_video_url.should be_nil
end
end
context "when encoding is available from panda but status has failed" do
it "should return nil" do
video.stub(:panda_video).and_return double(encodings: [double(panda_encoding_object(100, :fail))])
video.mp4_video_url.should be_nil
end
end
end
describe "#get_encoding" do
context "when encoding is unavailable from panda" do
it "should return nil" do
video.stub(:panda_video).and_return nil
video.get_encoding.should be_nil
end
end
context "when encoding is available from panda" do
it "should return panda object" do
video.stub(:panda_video).and_return double(encodings: [double(panda_encoding_object(100, :success))])
video.get_encoding.should eq video.panda_video.encodings.first
end
end
end
end
end
def panda_encoding_object progress, status
{ url: "http://hello.io", encoding_progress: progress, status: status.to_s }
end
I've looked at using the webmock
gem, but I am not sure that is going to accomplish what I am trying to do here. The error I am getting in my test is:
1) ManagesVideoFiles instance methods #thumbnail_url when panda can find video should return encoding object with screenshots
Failure/Error: video.thumbnail_url
Double received unexpected message :sub with ("http", "https")
# ./app/models/concerns/manages_video_files.rb:24:in `thumbnail_url'
# ./spec/concerns/manages_video_files_spec.rb:33:in `block (5 levels) in <top (required)>'
Upvotes: 0
Views: 1063
Reputation: 320
That error is occurring because your stub of the method encodings is returning an object that doesn't respond to the #sub
method (the line where you define the variable secure_screenshots
). The problem is that doubles raise errors when they get methods called on them that aren't stubbed out.
To get past this problem for now, you can add a definition for sub
in your panda encoding object at the bottom of your test, but that's just covering up a larger problem with this test file.
Mocking and stubbing is an uphill battled when you have classes that are trying to do too much. If you're building stubs (or doubles) for the results of stubs (or doubles), that's your tests telling you that it's time to break your class into smaller, simpler objects.
Upvotes: 1