title: Unit testing, mocking and traits in rust
body: <p>Iam current building a application which heavy relies on File IO, so obviously lots of parts of my code have <code>File::open(file)</code>.</p>
  <p>Doing some integration tests are ok, I can easily set folders to load file and scenarios needed for it.</p>
  <p>The problem comes whatever I want to unit tests, and code branches. I know there is lots of mocking libraries out there that claim to mocks, but i feel my biggest problem is code design itself.</p>
  <p>Let's say for instance, I would do the same code in any object oriented language (java in the example), i could write some interfaces, and on tests simple override the default behavior I want to mock, set the a fake <code>ClientRepository</code>, whatever reimplemented wih a fixed return, or use some mocking framework, like mockito.</p>
  <pre class="lang-java prettyprint-override"><code>
  public interface ClientRepository {
     Client getClient(int id)
  }
  
  public class ClientRepositoryDB {
     
    private ClientRepository repository;
    
    //getters and setters
  
    public Client getClientById(int id) {
      Client client = repository.getClient(id);
  
      //Some data manipulation and validation
    }
  }
  
  </code></pre>
  <p>But i couldn`t manage to get the same results in rust, since we endup mixing data with behavior.</p>
  <p>On the <a href="https://doc.rust-lang.org/1.33.0/book/ch15-05-interior-mutability.html#a-use-case-for-interior-mutability-mock-objects" rel="noreferrer">RefCell documentation</a>, there is a similar example with the one I gave on java. Some of answers points to traits, <a href="https://stackoverflow.com/questions/61941650/how-do-i-create-a-mock-function-in-rust">clojures</a>, <a href="https://klau.si/blog/mocking-in-rust-with-conditional-compilation/" rel="noreferrer">conditional compiliation</a></p>
  <p>We might come with some scenarios in test, first one a public function in some mod.rs</p>
  <pre class="lang-rust prettyprint-override"><code>
  
  #[derive(Serialize, Deserialize, Debug, Clone)]
  pub struct SomeData {
      pub name: Option&lt;String&gt;,
      pub address: Option&lt;String&gt;,
  }
  
  
  pub fn get_some_data(file_path: PathBuf) -&gt; Option&lt;SomeData&gt; {
      let mut contents = String::new();
  
  
      match File::open(file_path) {
          Ok(mut file) =&gt; {
              match file.read_to_string(&amp;mut contents) {
                  Ok(result) =&gt; result,
                  Err(_err) =&gt; panic!(
                      panic!(&quot;Problem reading file&quot;)
                  ),
              };
          }
          Err(err) =&gt; panic!(&quot;File not find&quot;),
      }
      
      // using serde for operate on data output
      let some_data: SomeData = match serde_json::from_str(&amp;contents) {
          Ok(some_data) =&gt; some_data,
          Err(err) =&gt; panic!(
              &quot;An error occour when parsing: {:?}&quot;,
              err
          ),
      };
  
      //we might do some checks or whatever here
      Some(some_data) or None
  }
  
  
  mod test {
  
      use super::*;
      
      #[test]
      fn test_if_scenario_a_happen() -&gt; std::io::Result&lt;()&gt; {
         //tied with File::open
         let some_data = get_some_data(PathBuf::new);
  
          assert!(result.is_some());
  
          Ok(())
      }
  
  
      #[test]
      fn test_if_scenario_b_happen() -&gt; std::io::Result&lt;()&gt; {
         //We might need to write two files, and we want to test is the logic, not the file loading itself
         let some_data = get_some_data(PathBuf::new);
  
          assert!(result.is_none());
  
          Ok(())
      }
  }
  </code></pre>
  <p>The second the same function becoming a trait and some struct implement it.</p>
  <pre class="lang-rust prettyprint-override"><code>
  
  
  #[derive(Serialize, Deserialize, Debug, Clone)]
  pub struct SomeData {
     pub name: Option&lt;String&gt;,
     pub address: Option&lt;String&gt;,
  }
  
  trait GetSomeData {
     fn get_some_data(&amp;self, file_path: PathBuf) -&gt; Option&lt;SomeData&gt;;
  }
  
  pub struct SomeDataService {}
  
  impl GetSomeData for SomeDataService {
     fn get_some_data(&amp;self, file_path: PathBuf) -&gt; Option&lt;SomeData&gt; {
         let mut contents = String::new();
  
         match File::open(file_path) {
             Ok(mut file) =&gt; {
                 match file.read_to_string(&amp;mut contents) {
                     Ok(result) =&gt; result,
                     Err(_err) =&gt; panic!(&quot;Problem reading file&quot;),
                 };
             }
             Err(err) =&gt; panic!(&quot;File not find&quot;),
         }
         // using serde for operate on data output
         let some_data: SomeData = match serde_json::from_str(&amp;contents) {
             Ok(some_data) =&gt; some_data,
             Err(err) =&gt; panic!(&quot;An error occour when parsing: {:?}&quot;, err),
         };
  
         //we might do some checks or whatever here
         Some(some_data) or None
     }
  }
  
  impl SomeDataService {
     pub fn do_something_with_data(&amp;self) -&gt; Option&lt;SomeData&gt; {
  
         self.get_some_data(PathBuf::new())
     }
  }
  
  
  mod test {
  
     use super::*;
     
     #[test]
     fn test_if_scenario_a_happen() -&gt; std::io::Result&lt;()&gt; {
        //tied with File::open
        let service = SomeDataService{}
  
        let some_data = service.do_something_with_data(PathBuf::new);
  
         assert!(result.is_some());
  
         Ok(())
     }
  
  }
  </code></pre>
  <p>On both examples, we have a hard time unit testing it, since we tied with <code>File::open</code>, and surely, this might be extend to any non-deterministic function, like time, db connection, etc.</p>
  <p>How would you design this or any similar code to make easier to unit testing and better design?</p>