Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Choose Your Own Testing Adventure

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

Choose Your Own Testing Adventure

Going through the software testing process is sort of like reading through a Choose Your Own Adventure® book. Our goal is to make testing choices that will lead to a happy ending.

Chooseco now owns the trademark to Choose Your Own Adventure®. You can find the online at https://www.cyoa.com/.

Avatar for Michael Stalker

Michael Stalker

February 10, 2015
Tweet

More Decks by Michael Stalker

Other Decks in Programming

Transcript

  1. – The Story of a Test Suite In which you,

    the Adventurer, And your band of Companions Set out to explore The Land of Testing.
  2. – ™ Should our tests interact with the database? ™ Should we

    use mocks? ™ Should we reuse test setup? ™ Should our tests call a remote service? ™ Should we give up if methods are hard to test? ™ Should we test error message text? Things Turn Confusing
  3. – ™ The test suite is slow ™ Tests break easily ™ Tests

    require too much setup ™ Tests are hard to write ™ Tests fail intermittently ™ Tests stay broken Dragon Smells
  4. – ™ To test because it's a Good Idea™, turn to

    slide 132. ™ To test because: – You want to verify basic correctness – You want to refactor more easily – You want to identify problems in your design – You want to catch regressions in the future – ...Turn to slide 12. Choices
  5. – ™ To test because it's a Good Idea™, turn to

    slide 132. ™ To test because: – You want to verify basic correctness – You want to refactor more easily – You want to identify problems in your design – You want to catch regressions in the future – ...Turn to slide 12. Choices
  6. class  User      attr_reader  :name        

     def  initialize(name:  'Unknown')          @name  =  name      end   end       class  Image      attr_reader  :id,  :user          def  initialize(user:  User.new)          @user  =  user          @id  =  #  generate  unique  id      end   end
  7. describe  Image  do      let(:user)  {  User.new  }  

       let(:image)  {  Image.new  }          describe  '#initialize'  do          it  'generates  an  ID'  do              expect(image.id).to  be          end              it  'sets  the  user'  do              image  =  Image.new(user:  user)              expect(image.user).to  eql(user)          end      end   end
  8. describe  Image  do      let(:user)  {  User.new  }  

       let(:image)  {  Image.new  }          describe  '#initialize'  do          it  'generates  an  ID'  do              expect(image.id).to  be          end              it  'sets  the  user'  do              image  =  Image.new(user:  user)              expect(image.user).to  eql(user)          end      end   end
  9. describe  Image  do      let(:user)  {  User.new  }  

       let(:image)  {  Image.new  }          describe  '#initialize'  do          it  'generates  an  ID'  do              expect(image.id).to  be          end              it  'sets  the  user'  do              image  =  Image.new(user:  user)              expect(image.user).to  eql(user)          end      end   end
  10. – Choices ™ To write your tests like this, turn to

    slide 51. ™ To use a test setup only when it applies to all tests in your block, turn to slide 78.
  11. – Choices ™ To write your tests like this, turn to

    slide 51. ™ To use a test setup only when it applies to all tests in your block, turn to slide 78.
  12. describe  Image  do      describe  '#initialize'  do    

         it  'generates  an  ID'  do              image  =  Image.new              expect(image.id).to  be          end              it  'sets  the  user'  do              user  =  User.new              image  =  Image.new(user:  user)              expect(image.user).to  eql(user)          end      end   end
  13. describe  Image  do      let(:user)  {  User.new(name:  'Moe')  }

         let(:image)  {  Image.new(user:  user)  }          #  100  lines  of  code          describe  '#user_name'  do          it  'says  who  uploaded  image'  do              user_name  =  image.user_name              expect(user_name).to  eql('Moe')          end      end   end
  14. – Choices ™ To write your tests like this, turn to

    slide 18. ™ To duplicate some test setup in several tests, turn to slide 31.
  15. – Choices ™ To write your tests like this, turn to

    slide 18. ™ To duplicate some test setup in several tests, turn to slide 31.
  16. describe  Image  do          #  100  lines

     of  code          describe  '#user_name'  do          it  'says  who  uploaded  image'  do              user  =  User.new(name:  'Moe')              image  =  Image.new(user:  user)              user_name  =  image.user_name              expect(user_name).to  eql('Moe')          end      end   end
  17. module  Postable      def  post        

     #  ...      end   end       class  BlogPost      include  Postable   end       class  Image      include  Postable   end
  18. describe  BlogPost  do      describe  '#post'  do    

         #  ...      end   end       describe  Image  do      describe  '#post'  do          #  ...      end   end
  19. – ™ To test your modules through classes that include them,

    turn to slide 117. ™ To create a dummy class to help test your modules, turn to slide 95. Choices
  20. – ™ To test your modules through classes that include them,

    turn to slide 117. ™ To create a dummy class to help test your modules, turn to slide 95. Choices
  21. class  TestPostable      include  Postable   end    

      describe  Postable  do      describe  '#post'  do          it  'creates  a  post'  do              postable  =  TestPostable.new              expect(postable.post).to  #...          end      end   end
  22. module  ImageHelper      def  name        

     "Image  #{params[:image_id]}"      end   end  
  23. – ™ To use RSpec Rails helper specs, turn to slide

    43. ™ To test helpers like any other module, turn to slide 64. Choices
  24. – ™ To use RSpec Rails helper specs, turn to slide

    43. ™ To test helpers like any other module, turn to slide 64. Choices
  25. module  ImageHelper      def  name        

     "Image  #{params[:image_id]}"      end   end  
  26. module  ImageHelper      def  name(id:  params[:image_id])      

       "Image  #{params[:image_id]}"      end   end  
  27. class  TestImageHelper      include  ImageHelper   end    

      describe  ImageHelper  do      describe  '#name'  do          it  'returns  an  image  name'  do              helper  =  TestImageHelper.new              name  =  helper.name(id:  4)              expect(name).to  eql('Image  4')          end      end   end  
  28. module  ImageHelper      def  name(id:)        

     "Image  #{id}"      end   end  
  29. class  User  <  ActiveRecord::Base      has_many  :friends,  through:  :friendships

         has_many  :friendships          def  befriend(friend)          friendships.create(friend:  friend)      end   end       class  Friendship  <  ActiveRecord::Base      belongs_to  :user      belongs_to  :friend,  class_name:  'User'   end  
  30. describe  User  do      describe  '#befriend'  do    

         it  'creates  a  friendship'  do              user  =  User.create              friend  =  User.create              user.befriend  friend              expect(user.friends.count).to  eql(1)              expect(Friendship.count).to  eql(1)          end      end   end  
  31. – Choices ™ To write tests that talk to the database,

    turn to slide 49. ™ To write tests that use mocks and stubs, turn to slide 104.
  32. class  User      def  self.password        

     SecureRandom.hex      end   end       User.password   #=>  "d929992ff842f257c89d8ad3cbb80f1b"       allow(User).to  receive(:password).                                and_return('hi')       User.password   #=>  "hi"  
  33. class  User      def  self.password        

     SecureRandom.hex      end   end       User.password   #=>  "d929992ff842f257c89d8ad3cbb80f1b"       allow(User).to  receive(:password).                                and_return('hi')       User.password   #=>  "hi"  
  34. class  User      def  self.password        

     SecureRandom.hex      end   end       User.password   #=>  "d929992ff842f257c89d8ad3cbb80f1b"       expect(User).to  receive(:password).                                  and_return('hi')       User.password   #=>  "hi"  
  35. – ™ With a stub, we allow User to receive the

    password message. ™ With a mock, we expect User to receive the password message. It Looks the Same to Me
  36. – ™ Mock – When you call a method on another object...

    – Or you want to talk to an external service... – And that operation has side effects. ™ Stub in all other cases. When Do You Mock?
  37. – Choices ™ To write tests that talk to the database,

    turn to slide 49. ™ To write tests that use mocks and stubs, turn to slide 104.
  38. – Choices ™ To write tests that talk to the database,

    turn to slide 49. ™ To write tests that use mocks and stubs, turn to slide 104.
  39. describe  User  do      describe  '#befriend'  do    

         it  'creates  a  friendship'  do              user  =  User.new              friend  =  User.new              friendships  =  Object.new              allow(user).to  receive(:friendships).                                            and_return(friendships)              expect(friendships).                  to  receive(:create).                  with(friend:  friend)              user.befriend  friend          end      end   end  
  40. describe  User  do      describe  '#befriend'  do    

         it  'creates  a  friendship'  do              user  =  User.new              friend  =  User.new              friendships  =  Object.new              allow(user).to  receive(:friendships).                                            and_return(friendships)              expect(friendships).                  to  receive(:create).                  with(friend:  friend)              user.befriend  friend          end      end   end  
  41. describe  User  do      describe  '#befriend'  do    

         it  'creates  a  friendship'  do              user  =  User.new              friend  =  User.new              friendships  =  Object.new              allow(user).to  receive(:friendships).                                            and_return(friendships)              expect(friendships).                  to  receive(:create).                  with(friend:  friend)              user.befriend  friend          end      end   end  
  42. describe  User  do      describe  '#befriend'  do    

         it  'creates  a  friendship'  do              user  =  User.new              friend  =  User.new              friendships  =  Object.new              allow(user).to  receive(:friendships).                                            and_return(friendships)              expect(friendships).                  to  receive(:create).                  with(friend:  friend)              user.befriend  friend          end      end   end  
  43. class  User  <  ActiveRecord::Base      has_many  :friendships    

     has_many  :friends,  through:  :friendships        def  befriend(friend)          friendships.create(friend:  friend)      end   end     class  Friendship  <  ActiveRecord::Base      belongs_to  :user      belongs_to  :friend,  class_name:  'User'   end  
  44. describe  User  do      describe  '#befriend'  do    

         it  'creates  a  friendship'  do              user  =  User.new              friend  =  User.new              friendships  =  Object.new              allow(user).to  receive(:friendships).                                            and_return(friendships)              expect(friendships).                  to  receive(:create).                  with(friend:  friend)              user.befriend  friend          end      end   end  
  45. describe  User  do      describe  '#befriend'  do    

         it  'creates  a  friendship'  do              user  =  User.new              friend  =  User.new              friendships  =  Object.new              allow(user).to  receive(:friendships).                                            and_return(friendships)              expect(friendships).                  to  receive(:create).                  with(friend:  friend)              user.befriend  friend          end      end   end  
  46. #  spec_helper.rb     RSpec.configure  do  |config|      config.mock_with

     :rspec  do  |mocks|          #  Prevents  you  from  mocking  or  stubbing          #  a  method  that  does  not  exist  on  a          #  real  object.  This  is  generally          #  recommended.          mocks.verify_partial_doubles  =  false      end   end  
  47. class  User      def  self.password        

     SecureRandom.hex      end   end  
  48. describe  User  do      describe  '.password'  do    

         it  'sets  a  password'  do              allow(SecureRandom).                  to  receive(:hex).                  and_return('hi')              expect(User.password).to  eql('hi')          end      end   end
  49. describe  User  do      describe  '.password'  do    

         it  'sets  a  password'  do              generator  =  OpenStruct.new(hex:  'hi')              password  =  User.password(generator)              expect(password).to  eql('hi')          end      end   end  
  50. class  User      def  cancel_account        

     friendships.each  {  |f|  f.destroy  }              #  35  lines  of  code...              data  =  RemoteAuth.fetch(self)          @success  =  !!data.auth.credentials          @success  =  true  if  self.admin?              #  43  lines  of  nested  conditionals...                    @success  &&  self.disable!      end   end  
  51. – 1.  Do whatever you need to do to get

    the code under test. 2.  Improve the code. 3.  Improve your tests. Testing Awful Code
  52. – ™ Test these with high-level acceptance tests. ™ These are not

    unit tests. ™ Test whatever your customers require. Testing Views
  53. – ™ “Mocks Aren’t Stubs” by Martin Fowler ™ Practical Object-Oriented Design

    in Ruby by Sandi Metz, Chapter 9 ™ Better Specs website: http://betterspecs.org/ ™ “Eradicating Non-Determinism in Tests” by Martin Fowler ™ Working Effectively with Legacy Code by Michael Feathers Resources
  54. – ™ "Magic Tricks of Testing" video by Sandi Metz ™ "The

    Deep Synergy Between Testability and Good Design" video by Michael Feathers ™ "Integrated Tests Are a Scam" by J. B. Rainsberger ™ Growing Object-Oriented Software, Guided by Tests by Steve Freeman and Nat Pryce Resources
  55. – ™  Princess: https://www.flickr.com/photos/partymonstrrrr/7316827188 ™  Stairs: https://www.flickr.com/photos/gadl/288607676/ ™  Fork: https://www.flickr.com/photos/james_wheeler/9468151425/in/photolist-fqEKy6-aoQZSe-aoTDkf-aoQpTe-bDvjFh-aoQSwX-obecdX-

    osGQuP-ousNGp-9YWC78-aLa7Xr-aL9ZZD-a6M8yk-azNXX8-cQH5i-8aFCyi-5Tm8ki-5GfYv1- NaWSn-9u1p76-9u5a9m-9u1hsB-7Xte9q-9wGrzK-9wJTQS-bgS4wt-fxqosn-7Xtfq1-oFSs4n-7Xtd8f-9u1yzB-fxqovF-aqxDuM-6ecY8M-7XqcBc- pYLqLL-gwPZT5-9wHi8E-7XtbVS-9wG2Ex-8wZJoN-6y4YNX-9wGFyZ-oppLGG-cX9kBG-8nXMfx-dj9TqW-4UdHYf-fSZfKw-hhSXSJ ™  Scaffolding: https://www.flickr.com/photos/ldm/14296081/in/photolist-2ggJa-4myKSw-puD54a-oTLyBM-CxLG9-5Ydz2c-5mCAiL-61wjbq- p3Cnx-gCPgU-GbAqX-mTCufc-AtiPD-6c917Q-8o7qEJ-2vGSqn-pei74m-zBk6f-2BWUfA-6BSGwe-chbj37-95FUn3-n8CpB1- oR6vrB-6BTnfr-7RGNc-r3Bay-7Bjx3X-2Ax8i-81yaU-fFz5Km-5c7bcQ-58ftpq-kMTAA3-o7rFHf-kTC7D-2Qu83N-5qGhKP-6xmHDy-2QpsTZ- e1EL6K-6uThwX-4WhnYr-jgjbyi-6o3d5M-6dgXV-7CCdmo-9T53yA-Mcs7-59nqz6 ™  Fragile: https://www.flickr.com/photos/motleye/299066723/in/photolist-sqN7P-2FKJdW-7tGnYi-4a113L-ZAmwd-56Nv5x- qvbVmR-92Kyy6-vfKPe-9JMT85-6p47kz-4vV9Lu-4EB1Mk-bKWJQZ-9UDVEj-7nVY7d- dPZ4Ai-8cgiwS-8rf7dd-4zKAvi-7FdymG-6JtUc5-7Pvwtk-8UqU1D-5evTWi-JZnqm-YACqD-7LgMJ-5cG3mE-u6FCP-LVbcE-bcWjf-PVzDe- agQsjv-2bXT1-cmaiQY-dWhD47-8u3LkG-8brFfM-5pmNuf-9XoYim-8DFyYi-4YRtwa-8DRaan-4v8tXj-77SaJB-fbdQLT-daiJH9-x5SEZ-85evxp ™  Shattered glass: https://www.flickr.com/photos/llreadll/3573278617/in/photolist-6rKZf2-9wMW41-auepW-fcq6Sn-9y7MJY-6wYJ93- hmpUsV-bdarj2-ipFk7P-hneMhN-7mWPp6-4Xikka-4yMuKd-9oe7DW-9kCF4D-55aqGQ-nWpoWs-nUsvEW-nYhnKF-nWcR4D-nE1o4c- nUsrRo-6yQYdG-fFJRgk-nWo5yf-nE1mVv-nE1wZ7-nYhit4-nE1vG7-nE1Eqw-4RstYi-jU4GZr-6yLTDB-6jj6iP-9yzyS9-5sCpkg-5gqPZS-8hau8B- dixF9v-nWcMdH-6EMigZ-5C3Kjr-n8jb7G-nE1DtS-eirzdV-6YY6st-5o5fBq-eAYX3-482GPi-nYhkrc ™  Roulette: https://www.flickr.com/photos/dahlstroms/5276348473/in/photolist-93fEzp-JfaHg-35MUP4-85EG4- oeJMvw-552jcY-85siop-7Zoewm-jwMLM5-85ECJ-bvk3Z2-jwP3qu-jwMNvq-bd5iG8-6HBj6o-q15ds-3LgDuT-bvk2P4-24fYe-kkux8c- fPvDam-8Edcnh-2inCkM-A2zMe-ettS6G-8YsJjo-85ESK-ecDJBz-9ZEmF5-7LYYdC-5WejBA-4K84MW-4k6Z9S-h1Egb-62LiHv-c7Es5- bqQP71-7LYZaf-7LYZ1h-7LYYQ7-7LYYvy-7LUZRi-7LYXKW-7LUZoe-7LUZep-7LYXkG-ds1dL-3htGiH-54t6Xs-5dkLUi ™  Head in sand: https://www.flickr.com/photos/12023825@N04/2898021822/in/photolist-5q67Vu-5eZ35e-6s3LMv-5kxw4o- CF6Mf-3dbCaX-3bcR41-6nDw8D-4HPZnj-4k6enD-A2ztT-3pGpRp-55zo6b-eVYp5-6aLURj-4gVAQh-6TWNsZ-68bTZR-e715B9-e6Ur3K- e714M7-e6UpYR-e713vA-e712Fq-kkuyJi-gok3nj-gokD9n-bTEW2K-itoqPn-9WRvGS-4Fog1W-5u6BTE-9pUy37- jtEN2c-4bLptM-2Vx99E-37XGWF-5J19Y9-bxEedx-4Fom7j-4Fojw1-4Fj4mM-4Foe9w-9BKXhj-4JvTxa-jwP1Jo-gokfRC-rhshf-7yd892-kPgMiW Photo Credits
  56. – ™  Dead end: https://www.flickr.com/photos/admaust/3652271486/in/photolist-6yJR53-7Cjksz-jyVaQ-ccyFx7-697Lo1-hUWDN-dPF5jL- pn3T3H-hUWDJ-9hXhsj-ehCiXi-uWZVP-54SD3T-fgFNwW-fgrzWi-666aDt-33sdMG-dGLkML-fgrwHZ-h6wSi1-3ar4sx-cewYs5- j1XQNa-8x8Mhx-dA6BQT-9vWSeV-fgryUB-fgrPY8-dPzpDt-fgFUco-fgFRTS-fgrCxa-fgrE7t-fgFWGG-fgrPbF-fgG46Y-fgFXGQ-fgrJ4B-dPzf2g- q7zHCB-eimrew-7DRMDe-6xahq3-4LAEzX-fxiMfr-eAui1P-81g9Eo-81gdnj-daiC92-btPK3T ™  Colored

    ropes: https://www.flickr.com/photos/derekbruff/7923579630 ™  Switchboard: https://www.flickr.com/photos/john_oshea/4484944821/in/ photolist-7QjvQR-7PFGoB-7PFFx4-7PJSEL-7PFDJ4-7PJQS9-7PFCeV-7PJPCj-7PFAXc-7PJNgQ-7PFAaV-7PFzWV-7PJLGJ-7PFyYR-7PJKRL-7PJJB 5-7PFwmD-7PFw1e-7PFvJg-7PFvpp-7PJG6C-7PFuje-7PFu4D-7PgcPJ-7Pcdza-7PcdwK-7Pcd8p-7LLJYp-7DUpsf-7Cg9s4-7PJFho-7PJENL-7Pi2fN -7Pe38n-7Pi229-7Pi1WC-7Pi1Ew-7PhUss-7PhUaw-7PgdsC-7Pgdpb-7PceaX-7Pgdkj-7Pce7k-7Pce5g-7Pce3V-7Pgddf-7PcdYB-7Pgd9N-7PcdUn ™  Dartboard: https://www.flickr.com/photos/modenadude/3280286776/in/photolist-5ZSjYy-7mwULw-98ZaVX-qgxQrk-kwr3wg- bXc6Nr-3t5Rre-9VWTG2-bpe8nT-bVHkvu-5AbmJU-cuqzWS-RDVWQ-bLkxC-5bje6L-mDfvU-4GvSvB-kwt9po-87YVmc-uo1r-5smnjs-CL6At- emAYd3-4s6DT-4s6CU-3wbWHS-RrWDs-cWz9Rf-8g4pLV-84HeXZ-aLiXcc-88Jcnx-4DCYsF-8NuypS-26erMn-5s3Vt1-6anxmk- msZRJ-3dZC5V-3a4uBb-4Qvpao-66mZ1h-87fJpK-87iVUS-aQL7Lg-4s6Ce-4rx9gB-3rtJJj-6UPf3p-A4VYA ™  Help key: https://www.flickr.com/photos/llauren/42440652/in/photolist-4Kw8o-7Vo5Zj-3nReW8-vsmJE-oCNzQL-bf2ecv- eiwhM1-7Lvaqu-7ntiiQ-V4RPF-avtc7U-7MaVuG-9sk6t4-bjxsyY-2R97kJ-6ZHmae-bf2eaF-6sUvAX-t8Rkn-aS4KWz-K5bqW-bf2e8Z- bf2e2g-7YtWQD-oYSo5a-5kRjMn-qcQWQd-cVnNMU-bf2e7P-kibQFh-7YDJb3-6ZHmmX-8pMZ2W-4ZagAF-5hZwdZ- bVpXwD-7w9QMb-6Jnxr1-baFaCV-6agmPN-gW12Do-h3vQbW-8wyXRz-inW8ZS-aKE6G-3jWBHb-6D7X7N-4mQaB9-98fCGk-9qG29R ™  Model airplane: https://www.flickr.com/photos/38978098@N03/8479068025/in/photolist-dVgrw2-dVgrvz-mAqqom-bt5sHq- bkox1b-9vdJFi-8ueRuL-pMTVcB-eb1VmY-dwbTmR-pLRy8g-bQnqfM-o3phyg-dHMWDH-oKGjGR-9g4TxP-6338pC-dsHD6h-57BLTE- mKqmQp-5Y4k6t-4Zs7Rn-cEFu25-9vgJtC-e1UZwk-nF2BNo-ndxYoi-p6Vy6q-byeiHp-p5qELV-ahtt74-5PfDES-aBSob4-cEFtP7-dJdUpJ-otcK2m- oQ17fA-8TE8k4-8TE8f2-9rzQU7-8TE8xg-9Fa6tp-24hqBN-dJ8qsx-24pzDM-25aurM-9NdQmT-23qvFi-dJdUM5-24caaZ ™  Ring of fire: https://www.flickr.com/photos/courosa/3786392249 ™  Elvis: "ElvisPresleyAlohafromHawaii" by Source. Licensed under Fair use via Wikipedia - http://en.wikipedia.org/wiki/ File:ElvisPresleyAlohafromHawaii.jpg#mediaviewer/File:ElvisPresleyAlohafromHawaii.jpg Photo Credits
  57. – ™  Elvis impersonator: https://www.flickr.com/photos/22197407@N04/3336836212/in/photolist-65Sa9Q-cwC7N-fwGZyg-sqkr- sqjW-8y4ydT-8y8rpG-cD6tZN-3oSne-cCXpLf-aeUsuq-8ZLiB-6G3wAo-cCXtXA-NLb56-cCXrVG- cD6vjd-6FYtmp-6FYs6c-6esPhp-cMJabq-cD6uAu-6FYt5F-cCXwCQ-cCXkkm-cMJkm3-cMJn4b-6FYutT-cMJkSo-cCXvy9- pwUqv2-cCXm45-cD6vzG-3rfLC-x8SWo-x2ZWG-6oksf-8psPuj-cCXqBN-cCXsT7-afsH3S-cMJ69q-37dnxd-g6kht9- cD6AvN-4Vc22L-cD6A1C-cD6ujQ-cCXnfE-9HxX9m ™ 

    Johnny Depp and Tony Angelotti: https://lh6.googleusercontent.com/-CQzo9ZttYMc/UfhSwVdYj0I/AAAAAAAAAPY/ PuX_XNn4RbE/w1101-h824-no/TonyAngelotti2.jpg. Used with permission. ™  Happily ever after: https://www.flickr.com/photos/stampinmom/5373581438 ™  Puzzle: https://www.flickr.com/photos/filu/4899342532/in/photolist-8sWpQY-iSEFkV-nLtYsi-9cfBr2- dKfwc5-5VxirZ-7UyLLa-9N7DnM-59ktec-59pCrN-6y2jMX-q6b1BC-6mSB7s-5UhnaA-6dpV1C-h82ub-4fUsNL- aSj57v-9N7Dc8-5Ycmai-8BPU1e-gJ3my-e3KE4-5B3jzN-G1RWd-5g6PTY-7vEVv7-6bZkwr-7vEVHQ-9boLH5-55TSMz- bpMqEM-8NLnCe-2QP4c-9bdfAr-4j1h7w-cee2wo-3KDNbn-p8FnFs-efQtxi-9SiXWP-7ASTkd-4jpvQH-7vB7fR- oGrQrW-57gbdz-4qB8yx-59pGDh-bqQCDE-oNLrbw ™  Dragon: http://pixabay.com/en/dragon-lizard-monster-chinese-149393/ Photo Credits