{"id":48266,"date":"2013-05-06T12:10:54","date_gmt":"2013-05-06T09:10:54","guid":{"rendered":"https:\/\/www.altoros.com\/blog\/?p=48266"},"modified":"2020-10-14T17:02:22","modified_gmt":"2020-10-14T14:02:22","slug":"lets-test-it-well-and-simply-and-smartly-2","status":"publish","type":"post","link":"https:\/\/www.altoros.com\/blog\/lets-test-it-well-and-simply-and-smartly-2\/","title":{"rendered":"Let&#8217;s Test It Well: Simply and Smartly"},"content":{"rendered":"<p>If you are fond of testing, just like our Ruby Developer Nastia Shaternik, you\u2019ll probably be interested to read her post about using RSpec. There, she dwells on how some RSpec features that are not commonly used can help you to simplify testing and make tests clearer.<\/p>\n<p>This article explains how to make tests readable as short documentation and how using <em>mock_model<\/em> can make your tests run faster. In addition, we exemplify the usage of RSpec\u2019s built-in expectations, two strategies of sharing the same data among different examples, etc.<\/p>\n<p>&nbsp;<\/p>\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_79_2 counter-hierarchy ez-toc-counter ez-toc-transparent ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Table of Contents<\/p>\n<span class=\"ez-toc-title-toggle\"><a href=\"#\" class=\"ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle\" aria-label=\"Toggle Table of Content\"><span class=\"ez-toc-js-icon-con\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/span><\/a><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/www.altoros.com\/blog\/lets-test-it-well-and-simply-and-smartly-2\/#Tests_as_specification\" >Tests as specification<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/www.altoros.com\/blog\/lets-test-it-well-and-simply-and-smartly-2\/#RSpecs_built-in_expectations\" >RSpec\u2019s built-in expectations<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/www.altoros.com\/blog\/lets-test-it-well-and-simply-and-smartly-2\/#mock_model_vs_stub_model\" >mock_model vs. stub_model<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/www.altoros.com\/blog\/lets-test-it-well-and-simply-and-smartly-2\/#subject_and_it\" >subject and it {}<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/www.altoros.com\/blog\/lets-test-it-well-and-simply-and-smartly-2\/#DRYness\" >DRY!ness<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/www.altoros.com\/blog\/lets-test-it-well-and-simply-and-smartly-2\/#Further_reading\" >Further reading<\/a><\/li><\/ul><\/nav><\/div>\n<h3><span class=\"ez-toc-section\" id=\"Tests_as_specification\"><\/span>Tests as specification<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>I&#8217;m really fond of tests, which can be read as short documentation and expose the application&#8217;s API. To help you to cope with it, run your specs with the <code style=\"color: black; background-color: #e6e6e6;\">--format d[ocumentation]<\/code> option. The output will be printed in a nested way. If you don\u2019t understand what your code can do, you should rewrite your tests. In order not to write RSpec options every time when running specs, create a <code style=\"color: black; background-color: #e6e6e6;\">.rspec<\/code> configuration file in your home or application directory. (Options that are stored in <code style=\"color: black; background-color: #e6e6e6;\">.\/.rspec<\/code> take  precedence over options stored in <code style=\"color: black; background-color: #e6e6e6;\">~\/.rspec<\/code>, and any options declared directly on the command line will take precedence over those in either file.) The <code style=\"color: black; background-color: #e6e6e6;\">.rspec<\/code> file will look as shown below.<\/p>\n<figure class=\"highlight\">\n<pre><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"o\">--<\/span><span class=\"n\">color<\/span>\r\n<span class=\"o\">--<\/span><span class=\"nb\">format<\/span> <span class=\"n\">d<\/span><span class=\"p\">[<\/span><span class=\"n\">ocumentation<\/span><span class=\"p\">]<\/span><\/code><\/pre>\n<\/figure>\n<p>&nbsp;<\/p>\n<h3><span class=\"ez-toc-section\" id=\"RSpecs_built-in_expectations\"><\/span>RSpec\u2019s built-in expectations<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Avoid using <code style=\"color: black; background-color: #e6e6e6;\">!=<\/code> and remember about <code style=\"color: black; background-color: #e6e6e6;\">should_not<\/code>. To test the <code style=\"color: black; background-color: #e6e6e6;\">actual.predicate?<\/code> methods, use <code style=\"color: black; background-color: #e6e6e6;\">actual.should be_[predicate]<\/code>.<\/p>\n<figure class=\"highlight\">\n<pre><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"n\">actual<\/span><span class=\"p\">.<\/span><span class=\"nf\">should<\/span> <span class=\"n\">be_true<\/span>  <span class=\"c1\"># passes if actual is truthy (not nil or false)<\/span>\r\n<span class=\"n\">actual<\/span><span class=\"p\">.<\/span><span class=\"nf\">should<\/span> <span class=\"n\">be_false<\/span> <span class=\"c1\"># passes if actual is falsy (nil or false)<\/span>\r\n<span class=\"n\">actual<\/span><span class=\"p\">.<\/span><span class=\"nf\">should<\/span> <span class=\"n\">be_nil<\/span>   <span class=\"c1\"># passes if actual is nil<\/span>\r\n<span class=\"n\">actual<\/span><span class=\"p\">.<\/span><span class=\"nf\">should<\/span> <span class=\"n\">be<\/span>       <span class=\"c1\"># passes if actual is truthy (not nil or false)<\/span><\/code><\/pre>\n<\/figure>\n<p>Please also use collection\u2019s matchers.<\/p>\n<figure class=\"highlight\">\n<pre><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"n\">actual<\/span><span class=\"p\">.<\/span><span class=\"nf\">should<\/span> <span class=\"kp\">include<\/span><span class=\"p\">(<\/span><span class=\"n\">expected<\/span><span class=\"p\">)<\/span>\r\n<span class=\"n\">actual<\/span><span class=\"p\">.<\/span><span class=\"nf\">should<\/span> <span class=\"n\">have<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span><span class=\"p\">).<\/span><span class=\"nf\">items<\/span>\r\n<span class=\"n\">actual<\/span><span class=\"p\">.<\/span><span class=\"nf\">should<\/span> <span class=\"n\">have_exactly<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span><span class=\"p\">).<\/span><span class=\"nf\">items<\/span>\r\n<span class=\"n\">actual<\/span><span class=\"p\">.<\/span><span class=\"nf\">should<\/span> <span class=\"n\">have_at_least<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span><span class=\"p\">).<\/span><span class=\"nf\">items<\/span>\r\n<span class=\"n\">actual<\/span><span class=\"p\">.<\/span><span class=\"nf\">should<\/span> <span class=\"n\">have_at_most<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span><span class=\"p\">).<\/span><span class=\"nf\">items<\/span><\/code><\/pre>\n<\/figure>\n<p>&nbsp;<\/p>\n<h3><span class=\"ez-toc-section\" id=\"mock_model_vs_stub_model\"><\/span><code style=\"color: #222222; background-color: #e6e6e6; padding: 1px 2px;\">mock_model<\/code> vs. <code style=\"color: #222222; background-color: #e6e6e6; padding: 1px 2px;\">stub_model<\/code><span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>By default, <code style=\"color: black; background-color: #e6e6e6;\">mock_model<\/code> produces a mock that acts like an existing record (<code style=\"color: black; background-color: #e6e6e6;\">persisted()<\/code> returns true). The <code style=\"color: black; background-color: #e6e6e6;\">stub_model<\/code> method is similar to <code style=\"color: black; background-color: #e6e6e6;\">mock_model<\/code> except that it creates an actual instance of the model. This requires that the model has a corresponding table in the database. So, the main advantage is obvious, tests written with <code style=\"color: black; background-color: #e6e6e6;\">mock_model<\/code>, will run faster. Another advantage of <code style=\"color: black; background-color: #e6e6e6;\">mock_model<\/code> over <code style=\"color: black; background-color: #e6e6e6;\">stub_model<\/code> is that it\u2019s a true double, so the examples are not dependent on the behavior\/misbehavior or even the existence of any other code.<\/p>\n<p>Usage of the <code style=\"color: black; background-color: #e6e6e6;\">mock_model<\/code> method is quite simple and is illustrated below.<\/p>\n<figure class=\"highlight\">\n<pre><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"n\">describe<\/span> <span class=\"no\">SpineData<\/span> <span class=\"k\">do<\/span>\r\n  <span class=\"n\">let<\/span><span class=\"p\">(<\/span><span class=\"ss\">:user<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span> <span class=\"n\">create<\/span> <span class=\"ss\">:user<\/span> <span class=\"p\">}<\/span>\r\n\r\n  <span class=\"n\">before<\/span><span class=\"p\">(<\/span><span class=\"ss\">:each<\/span><span class=\"p\">)<\/span> <span class=\"k\">do<\/span>\r\n    <span class=\"no\">SpineData<\/span><span class=\"p\">.<\/span><span class=\"nf\">stub_chain<\/span><span class=\"p\">(<\/span><span class=\"ss\">:controller<\/span><span class=\"p\">,<\/span> <span class=\"ss\">:current_user<\/span><span class=\"p\">).<\/span><span class=\"nf\">and_return<\/span><span class=\"p\">(<\/span><span class=\"n\">user<\/span><span class=\"p\">)<\/span>\r\n  <span class=\"k\">end<\/span>\r\n\r\n  <span class=\"c1\"># ...<\/span>\r\n\r\n  <span class=\"n\">context<\/span> <span class=\"s2\">\"dealing with content set\"<\/span> <span class=\"k\">do<\/span>\r\n    <span class=\"n\">let<\/span><span class=\"p\">(<\/span><span class=\"ss\">:set<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span> <span class=\"n\">mock_model<\/span> <span class=\"no\">ContentSet<\/span> <span class=\"p\">}<\/span>\r\n\r\n    <span class=\"n\">describe<\/span> <span class=\"s2\">\".set_updater\"<\/span> <span class=\"k\">do<\/span>\r\n      <span class=\"n\">subject<\/span> <span class=\"p\">{<\/span> <span class=\"no\">SpineData<\/span><span class=\"p\">.<\/span><span class=\"nf\">set_updater<\/span> <span class=\"n\">set<\/span> <span class=\"p\">}<\/span>\r\n\r\n      <span class=\"n\">it<\/span> <span class=\"p\">{<\/span> <span class=\"n\">should_not<\/span> <span class=\"n\">be_blank<\/span> <span class=\"p\">}<\/span>\r\n      <span class=\"n\">its<\/span><span class=\"p\">([<\/span><span class=\"ss\">:id<\/span><span class=\"p\">])<\/span> <span class=\"p\">{<\/span> <span class=\"n\">should<\/span> <span class=\"o\">==<\/span> <span class=\"n\">set<\/span><span class=\"p\">.<\/span><span class=\"nf\">id<\/span><span class=\"p\">}<\/span>\r\n    <span class=\"k\">end<\/span>\r\n  <span class=\"k\">end<\/span>\r\n<span class=\"k\">end<\/span><\/code><\/pre>\n<\/figure>\n<p>&nbsp;<\/p>\n<h3><span class=\"ez-toc-section\" id=\"subject_and_it\"><\/span><code style=\"color: #222222; background-color: #e6e6e6; padding: 1px 2px;\">subject<\/code> and <code style=\"color: #222222; background-color: #e6e6e6; padding: 1px 2px;\">it {}<\/code><span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>In an example group, you can use the <code style=\"color: black; background-color: #e6e6e6;\">subject<\/code> method to define an explicit subject for testing by passing it a block. Now, you can use the <code style=\"color: black; background-color: #e6e6e6;\">it {}<\/code> constructions to specify matchers. It\u2019s just concise!<\/p>\n<figure class=\"highlight\">\n<pre><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"n\">describe<\/span> <span class=\"no\">AccountProcessing<\/span> <span class=\"k\">do<\/span>\r\n  <span class=\"n\">include_context<\/span> <span class=\"ss\">:oauth_hash<\/span>\r\n\r\n  <span class=\"c1\"># ...<\/span>\r\n\r\n\r\n  <span class=\"n\">context<\/span> <span class=\"s1\">'user is anonymous'<\/span> <span class=\"k\">do<\/span>\r\n    <span class=\"n\">let<\/span><span class=\"p\">(<\/span><span class=\"ss\">:acc_processing<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span> <span class=\"no\">AccountProcessing<\/span><span class=\"p\">.<\/span><span class=\"nf\">new<\/span><span class=\"p\">(<\/span><span class=\"n\">auth_hash<\/span><span class=\"p\">)<\/span> <span class=\"p\">}<\/span>\r\n\r\n    <span class=\"c1\"># ...<\/span>\r\n\r\n    <span class=\"n\">describe<\/span> <span class=\"s1\">'#create_or_update_account'<\/span> <span class=\"k\">do<\/span>\r\n      <span class=\"n\">subject<\/span> <span class=\"p\">{<\/span> <span class=\"n\">acc_processing<\/span><span class=\"p\">.<\/span><span class=\"nf\">create_or_update_account<\/span> <span class=\"p\">}<\/span>\r\n      <span class=\"n\">it<\/span> <span class=\"p\">{<\/span> <span class=\"n\">should<\/span> <span class=\"n\">be_present<\/span> <span class=\"p\">}<\/span>\r\n    <span class=\"k\">end<\/span>\r\n\r\n    <span class=\"n\">describe<\/span> <span class=\"s1\">'#account_info'<\/span> <span class=\"k\">do<\/span>\r\n      <span class=\"n\">subject<\/span> <span class=\"p\">{<\/span> <span class=\"n\">acc_processing<\/span><span class=\"p\">.<\/span><span class=\"nf\">account_info<\/span> <span class=\"p\">}<\/span>\r\n\r\n      <span class=\"n\">it<\/span> <span class=\"s1\">'returns valid account info hash'<\/span> <span class=\"k\">do<\/span>\r\n        <span class=\"n\">should<\/span> <span class=\"n\">be<\/span> <span class=\"o\">==<\/span> <span class=\"p\">{<\/span> <span class=\"ss\">network: <\/span><span class=\"n\">auth_hash<\/span><span class=\"p\">[<\/span><span class=\"s1\">'provider'<\/span><span class=\"p\">],<\/span>\r\n                       <span class=\"ss\">email: <\/span><span class=\"n\">auth_hash<\/span><span class=\"p\">[<\/span><span class=\"s1\">'info'<\/span><span class=\"p\">][<\/span><span class=\"s1\">'email'<\/span><span class=\"p\">],<\/span>\r\n                       <span class=\"ss\">first_name: <\/span><span class=\"n\">auth_hash<\/span><span class=\"p\">[<\/span><span class=\"s1\">'info'<\/span><span class=\"p\">][<\/span><span class=\"s1\">'first_name'<\/span><span class=\"p\">],<\/span>\r\n                       <span class=\"ss\">last_name: <\/span><span class=\"n\">auth_hash<\/span><span class=\"p\">[<\/span><span class=\"s1\">'info'<\/span><span class=\"p\">][<\/span><span class=\"s1\">'last_name'<\/span><span class=\"p\">],<\/span>\r\n                       <span class=\"ss\">birthday: <\/span><span class=\"kp\">nil<\/span>\r\n        <span class=\"p\">}<\/span>\r\n      <span class=\"k\">end<\/span>\r\n    <span class=\"k\">end<\/span>\r\n\r\n  <span class=\"k\">end<\/span>\r\n\r\n<span class=\"k\">end<\/span><\/code><\/pre>\n<\/figure>\n<p>&nbsp;<\/p>\n<h3><span class=\"ez-toc-section\" id=\"DRYness\"><\/span><code style=\"color: #222222; background-color: #e6e6e6; padding: 1px 2px;\">DRY!ness<\/code><span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>There are two strategies\u2014<b>shared context<\/b> and <b>shared examples<\/b>\u2014to share the same data among different examples.<\/p>\n<p><b>Shared context<\/b><\/p>\n<p>Use <code style=\"color: black; background-color: #e6e6e6;\">shared_context<\/code> to define a block that will be evaluated in the context of example groups by employing <code style=\"color: black; background-color: #e6e6e6;\">include_context<\/code>. You can put settings (something in the <code style=\"color: black; background-color: #e6e6e6;\">before<\/code>\/<code style=\"color: black; background-color: #e6e6e6;\">after<\/code> block), variables, data, and methods. All the things you put into <code style=\"color: black; background-color: #e6e6e6;\">shared_contex<\/code> will be accessible in the example group by name.<\/p>\n<p>Below, you can see how to define <code style=\"color: black; background-color: #e6e6e6;\">shared_context<\/code>.<\/p>\n<figure class=\"highlight\">\n<pre><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"n\">shared_context<\/span> <span class=\"s2\">\"shared_data\"<\/span> <span class=\"k\">do<\/span>\r\n  <span class=\"n\">before<\/span> <span class=\"p\">{<\/span> <span class=\"vi\">@some_var<\/span> <span class=\"o\">=<\/span> <span class=\"ss\">:some_value<\/span> <span class=\"p\">}<\/span>\r\n\r\n  <span class=\"k\">def<\/span> <span class=\"nf\">shared_method<\/span>\r\n    <span class=\"s2\">\"it works\"<\/span>\r\n  <span class=\"k\">end<\/span>\r\n\r\n  <span class=\"n\">let<\/span><span class=\"p\">(<\/span><span class=\"ss\">:shared_let<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span> <span class=\"p\">{<\/span><span class=\"s1\">'arbitrary'<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"s1\">'object'<\/span><span class=\"p\">}<\/span> <span class=\"p\">}<\/span>\r\n\r\n  <span class=\"n\">subject<\/span> <span class=\"k\">do<\/span>\r\n    <span class=\"s1\">'this is the shared subject'<\/span>\r\n  <span class=\"k\">end<\/span>\r\n<span class=\"k\">end<\/span><\/code><\/pre>\n<\/figure>\n<p>Here is how you use <code style=\"color: black; background-color: #e6e6e6;\">shared_context<\/code>.<\/p>\n<figure class=\"highlight\">\n<pre><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"nb\">require<\/span> <span class=\"s2\">\".\/shared_data.rb\"<\/span>\r\n\r\n<span class=\"n\">describe<\/span> <span class=\"s2\">\"group that includes a shared context using 'include_context'\"<\/span> <span class=\"k\">do<\/span>\r\n  <span class=\"n\">include_context<\/span> <span class=\"ss\">:shared_data<\/span>\r\n\r\n  <span class=\"n\">it<\/span> <span class=\"s2\">\"has access to methods defined in shared context\"<\/span> <span class=\"k\">do<\/span>\r\n    <span class=\"n\">shared_method<\/span><span class=\"p\">.<\/span><span class=\"nf\">should<\/span> <span class=\"n\">eq<\/span><span class=\"p\">(<\/span><span class=\"s2\">\"it works\"<\/span><span class=\"p\">)<\/span>\r\n  <span class=\"k\">end<\/span>\r\n\r\n  <span class=\"n\">it<\/span> <span class=\"s2\">\"has access to methods defined with let in shared context\"<\/span> <span class=\"k\">do<\/span>\r\n    <span class=\"n\">shared_let<\/span><span class=\"p\">[<\/span><span class=\"s1\">'arbitrary'<\/span><span class=\"p\">].<\/span><span class=\"nf\">should<\/span> <span class=\"n\">eq<\/span><span class=\"p\">(<\/span><span class=\"s1\">'object'<\/span><span class=\"p\">)<\/span>\r\n  <span class=\"k\">end<\/span>\r\n\r\n  <span class=\"n\">it<\/span> <span class=\"s2\">\"runs the before hooks defined in the shared context\"<\/span> <span class=\"k\">do<\/span>\r\n    <span class=\"vi\">@some_var<\/span><span class=\"p\">.<\/span><span class=\"nf\">should<\/span> <span class=\"n\">be<\/span><span class=\"p\">(<\/span><span class=\"ss\">:some_value<\/span><span class=\"p\">)<\/span>\r\n  <span class=\"k\">end<\/span>\r\n\r\n  <span class=\"n\">it<\/span> <span class=\"s2\">\"accesses the subject defined in the shared context\"<\/span> <span class=\"k\">do<\/span>\r\n    <span class=\"n\">subject<\/span><span class=\"p\">.<\/span><span class=\"nf\">should<\/span> <span class=\"n\">eq<\/span><span class=\"p\">(<\/span><span class=\"s1\">'this is the shared subject'<\/span><span class=\"p\">)<\/span>\r\n  <span class=\"k\">end<\/span>\r\n<span class=\"k\">end<\/span><\/code><\/pre>\n<\/figure>\n<p><b>Shared examples<\/b><\/p>\n<p>Shared examples are used to describe a common behavior and encapsulate it into a single example group. Then, examples can be applied to another example group.<\/p>\n<p>This is how you define <code style=\"color: black; background-color: #e6e6e6;\">shared_examples<\/code>.<\/p>\n<figure class=\"highlight\">\n<pre><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"nb\">require<\/span> <span class=\"s2\">\"set\"<\/span>\r\n\r\n<span class=\"n\">shared_examples<\/span> <span class=\"s2\">\"a collection\"<\/span> <span class=\"k\">do<\/span>\r\n  <span class=\"n\">let<\/span><span class=\"p\">(<\/span><span class=\"ss\">:collection<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span> <span class=\"n\">described_class<\/span><span class=\"p\">.<\/span><span class=\"nf\">new<\/span><span class=\"p\">([<\/span><span class=\"mi\">7<\/span><span class=\"p\">,<\/span> <span class=\"mi\">2<\/span><span class=\"p\">,<\/span> <span class=\"mi\">4<\/span><span class=\"p\">])<\/span> <span class=\"p\">}<\/span>\r\n\r\n  <span class=\"n\">context<\/span> <span class=\"s2\">\"initialized with 3 items\"<\/span> <span class=\"k\">do<\/span>\r\n    <span class=\"n\">it<\/span> <span class=\"s2\">\"says it has three items\"<\/span> <span class=\"k\">do<\/span>\r\n      <span class=\"n\">collection<\/span><span class=\"p\">.<\/span><span class=\"nf\">size<\/span><span class=\"p\">.<\/span><span class=\"nf\">should<\/span> <span class=\"n\">eq<\/span><span class=\"p\">(<\/span><span class=\"mi\">3<\/span><span class=\"p\">)<\/span>\r\n    <span class=\"k\">end<\/span>\r\n  <span class=\"k\">end<\/span>\r\n\r\n  <span class=\"n\">describe<\/span> <span class=\"s2\">\"#include?\"<\/span> <span class=\"k\">do<\/span>\r\n    <span class=\"n\">context<\/span> <span class=\"s2\">\"with an an item that is in the collection\"<\/span> <span class=\"k\">do<\/span>\r\n      <span class=\"n\">it<\/span> <span class=\"s2\">\"returns true\"<\/span> <span class=\"k\">do<\/span>\r\n        <span class=\"n\">collection<\/span><span class=\"p\">.<\/span><span class=\"nf\">include?<\/span><span class=\"p\">(<\/span><span class=\"mi\">7<\/span><span class=\"p\">).<\/span><span class=\"nf\">should<\/span> <span class=\"n\">be_true<\/span>\r\n      <span class=\"k\">end<\/span>\r\n    <span class=\"k\">end<\/span>\r\n\r\n    <span class=\"n\">context<\/span> <span class=\"s2\">\"with an an item that is not in the collection\"<\/span> <span class=\"k\">do<\/span>\r\n      <span class=\"n\">it<\/span> <span class=\"s2\">\"returns false\"<\/span> <span class=\"k\">do<\/span>\r\n        <span class=\"n\">collection<\/span><span class=\"p\">.<\/span><span class=\"nf\">include?<\/span><span class=\"p\">(<\/span><span class=\"mi\">9<\/span><span class=\"p\">).<\/span><span class=\"nf\">should<\/span> <span class=\"n\">be_false<\/span>\r\n      <span class=\"k\">end<\/span>\r\n    <span class=\"k\">end<\/span>\r\n  <span class=\"k\">end<\/span>\r\n<span class=\"k\">end<\/span><\/code><\/pre>\n<\/figure>\n<p>Below, you can see how to use <code style=\"color: black; background-color: #e6e6e6;\">shared_examples<\/code>.<\/p>\n<figure class=\"highlight\">\n<pre><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"n\">describe<\/span> <span class=\"no\">Array<\/span> <span class=\"k\">do<\/span>\r\n  <span class=\"n\">it_behaves_like<\/span> <span class=\"s2\">\"a collection\"<\/span>\r\n<span class=\"k\">end<\/span>\r\n\r\n<span class=\"n\">describe<\/span> <span class=\"no\">Set<\/span> <span class=\"k\">do<\/span>\r\n  <span class=\"n\">it_behaves_like<\/span> <span class=\"s2\">\"a collection\"<\/span>\r\n<span class=\"k\">end<\/span><\/code><\/pre>\n<\/figure>\n<p>For more information about RSpec, you can consult with the <a href=\"https:\/\/relishapp.com\/rspec\/\" rel=\"noopener noreferrer\" target=\"_blank\">official documentation<\/a>. The <a href=\"https:\/\/pragprog.com\/search\/?q=the-rspec-book\" rel=\"noopener noreferrer\" target=\"_blank\">book<\/a> by RSpec\u2019s creator David Chelimsky will also be helpful. Or, you can opt for <a href=\"https:\/\/www.betterspecs.org\/\" rel=\"noopener noreferrer\" target=\"_blank\">these guides<\/a> on Better Specs.<\/p>\n<p>&nbsp;<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Further_reading\"><\/span>Further reading<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<ul>\n<li><a href=\"https:\/\/www.altoros.com\/blog\/how-to-integrate-independent-qa-testing-to-shorten-development-cycles\/\">How to Integrate Independent QA Testing to Shorten Development Cycles<\/a><\/li>\n<li><a href=\"https:\/\/www.altoros.com\/blog\/running-capybara-tests-in-remote-browsers\/\">Running \u0421apybara Tests in Remote Browsers<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Carrierwave gem and it&#8217;s inner workings, organizing switching content between private and public containers<\/p>\n","protected":false},"author":48,"featured_media":57484,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"content-type":"","footnotes":"","_links_to":"","_links_to_target":""},"categories":[214],"tags":[1000,895],"class_list":["post-48266","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tutorials","tag-github","tag-research-and-development"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.6 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Let&#039;s Test It Well: Simply and Smartly | Altoros<\/title>\n<meta name=\"description\" content=\"Learn how to write readable tests, what the difference between mock_model and stub_model is, how to use shared_context and shared_examples, etc.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.altoros.com\/blog\/lets-test-it-well-and-simply-and-smartly-2\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Let&#039;s Test It Well: Simply and Smartly | Altoros\" \/>\n<meta property=\"og:description\" content=\"Useful tips about RSpec to start following if you haven&#039;t done it yet\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.altoros.com\/blog\/lets-test-it-well-and-simply-and-smartly-2\/\" \/>\n<meta property=\"og:site_name\" content=\"Altoros\" \/>\n<meta property=\"article:published_time\" content=\"2013-05-06T09:10:54+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2020-10-14T14:02:22+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2013\/05\/testing-application-using-rspec.gif\" \/>\n\t<meta property=\"og:image:width\" content=\"898\" \/>\n\t<meta property=\"og:image:height\" content=\"521\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/gif\" \/>\n<meta name=\"author\" content=\"Anastasia Shaternik\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Anastasia Shaternik\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.altoros.com\/blog\/lets-test-it-well-and-simply-and-smartly-2\/\",\"url\":\"https:\/\/www.altoros.com\/blog\/lets-test-it-well-and-simply-and-smartly-2\/\",\"name\":\"Let's Test It Well: Simply and Smartly | Altoros\",\"isPartOf\":{\"@id\":\"https:\/\/www.altoros.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.altoros.com\/blog\/lets-test-it-well-and-simply-and-smartly-2\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.altoros.com\/blog\/lets-test-it-well-and-simply-and-smartly-2\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2013\/05\/testing-application-using-rspec.gif\",\"datePublished\":\"2013-05-06T09:10:54+00:00\",\"dateModified\":\"2020-10-14T14:02:22+00:00\",\"author\":{\"@id\":\"https:\/\/www.altoros.com\/blog\/#\/schema\/person\/3b61f82b7538ee2b1abe1d3d5ec67d9a\"},\"description\":\"Useful tips about RSpec to start following if you haven't done it yet\",\"breadcrumb\":{\"@id\":\"https:\/\/www.altoros.com\/blog\/lets-test-it-well-and-simply-and-smartly-2\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.altoros.com\/blog\/lets-test-it-well-and-simply-and-smartly-2\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.altoros.com\/blog\/lets-test-it-well-and-simply-and-smartly-2\/#primaryimage\",\"url\":\"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2013\/05\/testing-application-using-rspec.gif\",\"contentUrl\":\"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2013\/05\/testing-application-using-rspec.gif\",\"width\":898,\"height\":521},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.altoros.com\/blog\/lets-test-it-well-and-simply-and-smartly-2\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.altoros.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Let&#8217;s Test It Well: Simply and Smartly\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.altoros.com\/blog\/#website\",\"url\":\"https:\/\/www.altoros.com\/blog\/\",\"name\":\"Altoros\",\"description\":\"Insight\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.altoros.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.altoros.com\/blog\/#\/schema\/person\/3b61f82b7538ee2b1abe1d3d5ec67d9a\",\"name\":\"Anastasia Shaternik\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.altoros.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2019\/12\/11872253-96x96.jpg\",\"contentUrl\":\"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2019\/12\/11872253-96x96.jpg\",\"caption\":\"Anastasia Shaternik\"},\"description\":\"Nastia Shaternik is Software Developer with 5+ years of experience in software development. Did a lot of code refactoring backed with tests.\",\"sameAs\":[\"http:\/\/altoros.com\",\"https:\/\/www.linkedin.com\/in\/schaternik\/\"],\"url\":\"https:\/\/www.altoros.com\/blog\/author\/anastasia-shaternik\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Let's Test It Well: Simply and Smartly | Altoros","description":"Learn how to write readable tests, what the difference between mock_model and stub_model is, how to use shared_context and shared_examples, etc.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.altoros.com\/blog\/lets-test-it-well-and-simply-and-smartly-2\/","og_locale":"en_US","og_type":"article","og_title":"Let's Test It Well: Simply and Smartly | Altoros","og_description":"Useful tips about RSpec to start following if you haven't done it yet","og_url":"https:\/\/www.altoros.com\/blog\/lets-test-it-well-and-simply-and-smartly-2\/","og_site_name":"Altoros","article_published_time":"2013-05-06T09:10:54+00:00","article_modified_time":"2020-10-14T14:02:22+00:00","og_image":[{"width":898,"height":521,"url":"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2013\/05\/testing-application-using-rspec.gif","type":"image\/gif"}],"author":"Anastasia Shaternik","twitter_misc":{"Written by":"Anastasia Shaternik","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.altoros.com\/blog\/lets-test-it-well-and-simply-and-smartly-2\/","url":"https:\/\/www.altoros.com\/blog\/lets-test-it-well-and-simply-and-smartly-2\/","name":"Let's Test It Well: Simply and Smartly | Altoros","isPartOf":{"@id":"https:\/\/www.altoros.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.altoros.com\/blog\/lets-test-it-well-and-simply-and-smartly-2\/#primaryimage"},"image":{"@id":"https:\/\/www.altoros.com\/blog\/lets-test-it-well-and-simply-and-smartly-2\/#primaryimage"},"thumbnailUrl":"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2013\/05\/testing-application-using-rspec.gif","datePublished":"2013-05-06T09:10:54+00:00","dateModified":"2020-10-14T14:02:22+00:00","author":{"@id":"https:\/\/www.altoros.com\/blog\/#\/schema\/person\/3b61f82b7538ee2b1abe1d3d5ec67d9a"},"description":"Useful tips about RSpec to start following if you haven't done it yet","breadcrumb":{"@id":"https:\/\/www.altoros.com\/blog\/lets-test-it-well-and-simply-and-smartly-2\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.altoros.com\/blog\/lets-test-it-well-and-simply-and-smartly-2\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.altoros.com\/blog\/lets-test-it-well-and-simply-and-smartly-2\/#primaryimage","url":"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2013\/05\/testing-application-using-rspec.gif","contentUrl":"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2013\/05\/testing-application-using-rspec.gif","width":898,"height":521},{"@type":"BreadcrumbList","@id":"https:\/\/www.altoros.com\/blog\/lets-test-it-well-and-simply-and-smartly-2\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.altoros.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Let&#8217;s Test It Well: Simply and Smartly"}]},{"@type":"WebSite","@id":"https:\/\/www.altoros.com\/blog\/#website","url":"https:\/\/www.altoros.com\/blog\/","name":"Altoros","description":"Insight","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.altoros.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.altoros.com\/blog\/#\/schema\/person\/3b61f82b7538ee2b1abe1d3d5ec67d9a","name":"Anastasia Shaternik","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.altoros.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2019\/12\/11872253-96x96.jpg","contentUrl":"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2019\/12\/11872253-96x96.jpg","caption":"Anastasia Shaternik"},"description":"Nastia Shaternik is Software Developer with 5+ years of experience in software development. Did a lot of code refactoring backed with tests.","sameAs":["http:\/\/altoros.com","https:\/\/www.linkedin.com\/in\/schaternik\/"],"url":"https:\/\/www.altoros.com\/blog\/author\/anastasia-shaternik\/"}]}},"_links":{"self":[{"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/posts\/48266","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/users\/48"}],"replies":[{"embeddable":true,"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/comments?post=48266"}],"version-history":[{"count":14,"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/posts\/48266\/revisions"}],"predecessor-version":[{"id":57936,"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/posts\/48266\/revisions\/57936"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/media\/57484"}],"wp:attachment":[{"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/media?parent=48266"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/categories?post=48266"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/tags?post=48266"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}