<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Panagiotis Georgiadis</title>
    <description>The latest articles on DEV Community by Panagiotis Georgiadis (@drpaneas).</description>
    <link>https://dev.to/drpaneas</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F536918%2F3de6a321-7133-4da6-87ee-672956e3b2e5.jpeg</url>
      <title>DEV Community: Panagiotis Georgiadis</title>
      <link>https://dev.to/drpaneas</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/drpaneas"/>
    <language>en</language>
    <item>
      <title>GitOps in a nutshell </title>
      <dc:creator>Panagiotis Georgiadis</dc:creator>
      <pubDate>Tue, 04 Jan 2022 14:33:29 +0000</pubDate>
      <link>https://dev.to/drpaneas/gitops-in-a-nutshell-44m8</link>
      <guid>https://dev.to/drpaneas/gitops-in-a-nutshell-44m8</guid>
      <description>&lt;h1&gt;
  
  
  What GitOps is
&lt;/h1&gt;

&lt;p&gt;GitOps is a set of best practices to update or rollback your application, nowadays mostly in a cloud (e.g. k8s) environment. As the name implies, the whole process is controlled by Git, and the code includes both the application source and the infrastructure configuration. The goal, &lt;em&gt;as usual&lt;/em&gt;, is to deploy fast and reliably.&lt;/p&gt;

&lt;p&gt;In 2021, the &lt;a href="https://github.com/open-gitops/documents/blob/v1.0.0/PRINCIPLES.md"&gt;first OpenGitOps Standard v1&lt;/a&gt; was created, to make sure we all GitOps enthusiasts speak the same language. For more information go to &lt;a href="https://opengitops.dev/"&gt;opengitops.dev&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Hm, what about DevOps?
&lt;/h4&gt;

&lt;p&gt;DevOps is a mindset. GitOps is a set of best practices for deployments. They can both co-exist together.&lt;/p&gt;

&lt;h2&gt;
  
  
  So what those "best" practices say?
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;The entire system (infra &amp;amp; apps or services) is described in a declarative way. Imagine like taking a cab, you tell the taxi driver where you would like to go (declarative way), instead of giving him instructions in GoogleMaps fashion (e.g. turn here - turn there).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;pseudocode example&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (SERVER is online) {
    if (SERVER == Ubuntu)    {use apt-get}
    if (SERVER == Fedora)    {use dnf}
    if (SERVER == SUSE)      {use zypper}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;The desired state is versioned in Git, giving you the confidence that it cannot easily &lt;em&gt;just&lt;/em&gt; change, and &lt;em&gt;if that happens&lt;/em&gt;, then there will be a log entry about it, with a complete history.&lt;/li&gt;
&lt;li&gt;Merged PRs are applied to the system automatically or semi-automatically (meaning to inform the admin a new desirable state has been detected, so they can decide when to apply it).&lt;/li&gt;
&lt;li&gt;If there is a drift, reconciliation should detect this and try to fix it. If it cannot be fixed after a couple of minutes later, then an alert should be fired.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Given Kubernetes is the new platform to deploy apps in scale, let's see two deployment scenarios: one with GitOps and one without.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How to deploy in k8s without GitOps
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Someone commits the source code for the app in Github, the CI system runs the tests and builds the container and pushes it into a container registry.&lt;/li&gt;
&lt;li&gt;The CI (or another system) that has access to the k8s cluster, creates a deployment of the app using a bash script full of &lt;code&gt;kubectl&lt;/code&gt;, &lt;code&gt;helm&lt;/code&gt;, or any other command to interact with the cluster.&lt;/li&gt;
&lt;li&gt;The application should now be deployed on the k8s cluster. Hopefully there were no problems.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Problems with this workflow&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The cluster status is changing using &lt;code&gt;kubectl&lt;/code&gt; commands provided via a script or other programs talking directly with the API.&lt;/li&gt;
&lt;li&gt;The CI system has some kind of authorized access to the k8s cluster, and usually, this CI system is hosted somewhere externally, unless you have the tech &amp;amp; budget to build everything internally.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to deploy in k8s with GitOps
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;First step is the same: someone commits the source code for the app in Github, the CI system runs the tests and builds the container and pushes it into a container registry.&lt;/li&gt;
&lt;li&gt;Someone (or another system) goes into another repository, the one that holds the the k8s manifests for the app and makes the necessary changes (e.g. update the container image tag the newly built one).&lt;/li&gt;
&lt;li&gt;A k8s GitOps controller running into the cluster monitors this repo and detects this change. So it applies the new changes to the cluster according to the git repo.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Solutions used:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;State is changed based on manifests, not commands or interacting on the fly with the API.&lt;/li&gt;
&lt;li&gt;No external system needs access to the k8s cluster. The change is happening from within the cluster itself.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  GitOps use-case examples
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Most common scenario for GitOps is for continuous deployment. If you use k8s and you handle your apps and services in a declarative manner, this is the most straightforward way of deploying them.&lt;/li&gt;
&lt;li&gt;Easy roll-back of anything you deploy in your cluster no matter if you develop it or not. e.g. some databases or some monitoring tools. You can also deploy them in a similar fashion.&lt;/li&gt;
&lt;li&gt;Detects configuration drift, meaning someone is doing stuff while they shouldn't.&lt;/li&gt;
&lt;li&gt;Multi cluster scenario. When you have more than one cluster the usual question is what is running where and who changed what, when, why and so on. Having a git history and each cluster config in git, gives you all the answer you need without cluster debugging -- just &lt;code&gt;git diff&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  However, some might still don't adopt GitOps because ...
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Git is not your cup of tea (duh!)&lt;/li&gt;
&lt;li&gt;If you want to debug something on the cluster, it might be that the GitOps controller restores your changes back to the desired state. So you might want to disable it while doing this.&lt;/li&gt;
&lt;li&gt;GitOps is all about the deployment. For everything else (testing, building, monitoring, etc), you need to figure it out on your own.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are looking for a full blown solution to set everything up for you with one click, have a look at &lt;a href="https://docs.openshift.com/container-platform/4.7/cicd/gitops/understanding-openshift-gitops.html"&gt;https://docs.openshift.com/container-platform/4.7/cicd/gitops/understanding-openshift-gitops.html&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Mocking the filesystem in Go using Afero</title>
      <dc:creator>Panagiotis Georgiadis</dc:creator>
      <pubDate>Wed, 16 Dec 2020 17:21:06 +0000</pubDate>
      <link>https://dev.to/drpaneas/mocking-the-filesystem-in-go-using-afero-ok4</link>
      <guid>https://dev.to/drpaneas/mocking-the-filesystem-in-go-using-afero-ok4</guid>
      <description>&lt;p&gt;Let's start the project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="nv"&gt;$GOPATH&lt;/span&gt;/src/github.com/drpaneas
&lt;span class="nb"&gt;mkdir &lt;/span&gt;checkfile&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;checkfile
git init &lt;span class="nt"&gt;-q&lt;/span&gt;
go mod init
&lt;span class="nb"&gt;touch &lt;/span&gt;main.go
code &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="c"&gt;# for vscode&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Coding Task
&lt;/h2&gt;

&lt;p&gt;Write a function that checks if a specific directory exists on disk. &lt;em&gt;For example&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;folderExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;// do something&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bonus: Feel free to add &lt;code&gt;fileExists(filename)&lt;/code&gt; as homework.&lt;/p&gt;

&lt;h3&gt;
  
  
  Acceptance Criteria
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;a href="https://github.com/spf13/afero"&gt;https://github.com/spf13/afero&lt;/a&gt; for filesystem abstraction&lt;/li&gt;
&lt;li&gt;Make sure it works cross-platform&lt;/li&gt;
&lt;li&gt;For logging use &lt;a href="https://github.com/Sirupsen/logrus"&gt;https://github.com/Sirupsen/logrus&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Put the function into &lt;code&gt;pkg/utils&lt;/code&gt; package&lt;/li&gt;
&lt;li&gt;Write a unit test&lt;/li&gt;
&lt;li&gt;Make sure there are &lt;a href="https://blog.golang.org/examples"&gt;testable examples&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Hints&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Writing a unit test for filesystem checking is not trivial. You should NOT create a real file on the system, because then your test will depend on the I/O of the file system itself. The last resort is mocking the filesystem. There are quite a few powerful libraries like spf13/afero for this purpose (mocking of a filesystem). These packages will create temporary files in the background and clean up afterward.&lt;/li&gt;
&lt;li&gt;As an exercise, try to write the test first. Let it fail. Then try to fix it, by writing the actual implementation of the function.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Extra Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://golangcode.com/check-if-a-file-exists/"&gt;https://golangcode.com/check-if-a-file-exists/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=ifBUfIb7kdo"&gt;https://www.youtube.com/watch?v=ifBUfIb7kdo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/spf13/afero#using-afero-for-testing"&gt;https://github.com/spf13/afero#using-afero-for-testing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;An example using Afero for testing: &lt;a href="http://krsacme.com/golang-fs-tests/"&gt;http://krsacme.com/golang-fs-tests/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;For logging &lt;a href="https://linuxhint.com/golang-logrus-package/"&gt;https://linuxhint.com/golang-logrus-package/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;NOTICE&lt;/strong&gt;: &lt;/p&gt;

&lt;p&gt;If you are unable to mock this test, in worst case scenario, create a folder &lt;code&gt;pkg/utils/testdata&lt;/code&gt; and put actual files you can use for your test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's code
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// main.go&lt;/span&gt;
&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"os"&lt;/span&gt;

    &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="s"&gt;"github.com/sirupsen/logrus"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// exists reports whether the named file or directory exists&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;isDir&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Path is empty"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsNotExist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c"&gt;// look for the specific error type&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;isDir&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsDir&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// FolderExists reports whether the provided directory exists.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;FolderExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// FileExists reports whether the provided directory exists.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;FileExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Just for demo purposes&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;FolderExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"logs"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Folder exists"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Folder does not exist"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;FileExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"helloworld.txt"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"File exists"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"File does not exist"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One way to test this is by actually using the program itself.&lt;br&gt;
Running it as it is, it's expected to fail:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ERRO[0000] Folder does not exist                        
ERRO[0000] Folder does not exist
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we create the two necessary things we look for, then it's expected to work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create the file and directory&lt;/span&gt;
&lt;span class="nb"&gt;touch &lt;/span&gt;helloworld.txt
&lt;span class="nb"&gt;mkdir &lt;/span&gt;logs

&lt;span class="c"&gt;# Run it again&lt;/span&gt;
go run main.go
INFO[0000] Folder exists                                
INFO[0000] File exists
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Normally you would create separate package and not use &lt;code&gt;main&lt;/code&gt;.&lt;br&gt;
So let's do it!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; pkg/utils/
&lt;span class="nb"&gt;touch &lt;/span&gt;pkg/utils/filesystem.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// main.go&lt;/span&gt;
&lt;span class="c"&gt;// -------&lt;/span&gt;

&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/drpaneas/checkfile/pkg/utils"&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="s"&gt;"github.com/sirupsen/logrus"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;utils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FolderExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"logs"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Folder exists"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Folder does not exist"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;utils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FileExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"helloworld.txt"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"File exists"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"File does not exist"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// pkg/utils/filesystem.go&lt;/span&gt;
&lt;span class="c"&gt;// -----------------------&lt;/span&gt;

&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;utils&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"os"&lt;/span&gt;

    &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="s"&gt;"github.com/sirupsen/logrus"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// exists reports whether the named file or directory exists&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;isDir&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Path is empty"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsNotExist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c"&gt;// look for the specific error type&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;isDir&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsDir&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// FolderExists reports whether the provided directory exists.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;FolderExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// FileExists reports whether the provided directory exists.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;FileExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just to be on the safe side we didn't forget anything major, let's run it again to make sure everything is alright.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Run it again&lt;/span&gt;
go run main.go
INFO[0000] Folder exists                                
INFO[0000] File exists
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Test with testdata
&lt;/h2&gt;

&lt;p&gt;Ok,we need to write tests for &lt;code&gt;pkg/utils/filesystem.go&lt;/code&gt;.&lt;br&gt;
One way of doing this is by accessing a real file system to do testing, then we're talking about what you'd call system or integration testing. That's fine in itself: for instance, you could run such tests in a throw-away container as part of a CI pipeline.&lt;br&gt;
But with this approach you can't sensibly do what is called unit-testing.&lt;/p&gt;

&lt;p&gt;To proceed with that, we are going to use the generated boilerplate code that &lt;code&gt;vscode&lt;/code&gt; happily offers (give you have the Go extensions installed).&lt;/p&gt;

&lt;p&gt;Place the mouse cursor over the &lt;code&gt;FolderExists()&lt;/code&gt; function and press the keys: &lt;code&gt;CTRL+SHIFT+P&lt;/code&gt;.&lt;br&gt;
From the drop-down menu, type: &lt;code&gt;Go: test&lt;/code&gt; and select the one for the function.&lt;br&gt;
This will create the &lt;code&gt;filesystem_test.go&lt;/code&gt; file and populate it with a table test.&lt;br&gt;
Add your test logic there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// pkg/utils/filesystem_test.go&lt;/span&gt;
&lt;span class="c"&gt;// ----------------------------&lt;/span&gt;

&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;utils&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"testing"&lt;/span&gt;

&lt;span class="c"&gt;// Add those variables as well&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;existingFolder&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"./testdata/a-folder-that-exists"&lt;/span&gt;
    &lt;span class="n"&gt;nonExistingFolder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"./testdata/a-folder-that-does-not-exists"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestFolderExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;tests&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
        &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;
        &lt;span class="n"&gt;want&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;
    &lt;span class="p"&gt;}{&lt;/span&gt;
        &lt;span class="c"&gt;// ----- test logic start ----- //&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;"Returns true when given folder exists"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;existingFolder&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;"Returns false when given folder does not exist"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;nonExistingFolder&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="c"&gt;// ----- test logic end ----- //&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tt&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;FolderExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;tt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;want&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"FolderExists() = %v, want %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;got&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;want&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tests is relying upon real data on the actual hard drive.&lt;br&gt;
Run tests and you will see they will fail:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="o"&gt;./...&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;
&lt;span class="err"&gt;?&lt;/span&gt;       &lt;span class="n"&gt;github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;drpaneas&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;checkfile&lt;/span&gt;   &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;no&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="n"&gt;RUN&lt;/span&gt;   &lt;span class="n"&gt;TestFolderExists&lt;/span&gt;
&lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="n"&gt;RUN&lt;/span&gt;   &lt;span class="n"&gt;TestFolderExists&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Returns_true_when_given_folder_exists&lt;/span&gt;
    &lt;span class="n"&gt;filesystem_test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;33&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;FolderExists&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;want&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="n"&gt;RUN&lt;/span&gt;   &lt;span class="n"&gt;TestFolderExists&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Returns_false_when_given_folder_does_not_exist&lt;/span&gt;
&lt;span class="o"&gt;---&lt;/span&gt; &lt;span class="n"&gt;FAIL&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TestFolderExists&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0.00&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;---&lt;/span&gt; &lt;span class="n"&gt;FAIL&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TestFolderExists&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Returns_true_when_given_folder_exists&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0.00&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;---&lt;/span&gt; &lt;span class="n"&gt;PASS&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TestFolderExists&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Returns_false_when_given_folder_does_not_exist&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0.00&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;FAIL&lt;/span&gt;
&lt;span class="n"&gt;FAIL&lt;/span&gt;    &lt;span class="n"&gt;github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;drpaneas&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;checkfile&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;pkg&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;utils&lt;/span&gt; &lt;span class="m"&gt;0.098&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;span class="n"&gt;FAIL&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create the necessary testdata and try again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; pkg/utils/testdata/a-folder-that-exists
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;go &lt;span class="nb"&gt;test&lt;/span&gt; ./... &lt;span class="nt"&gt;-v&lt;/span&gt;?       github.com/drpaneas/checkfile   &lt;span class="o"&gt;[&lt;/span&gt;no &lt;span class="nb"&gt;test &lt;/span&gt;files]
&lt;span class="o"&gt;===&lt;/span&gt; RUN   TestFolderExists
&lt;span class="o"&gt;===&lt;/span&gt; RUN   TestFolderExists/Returns_true_when_given_folder_exists
&lt;span class="o"&gt;===&lt;/span&gt; RUN   TestFolderExists/Returns_false_when_given_folder_does_not_exist
&lt;span class="nt"&gt;---&lt;/span&gt; PASS: TestFolderExists &lt;span class="o"&gt;(&lt;/span&gt;0.00s&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nt"&gt;---&lt;/span&gt; PASS: TestFolderExists/Returns_true_when_given_folder_exists &lt;span class="o"&gt;(&lt;/span&gt;0.00s&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nt"&gt;---&lt;/span&gt; PASS: TestFolderExists/Returns_false_when_given_folder_does_not_exist &lt;span class="o"&gt;(&lt;/span&gt;0.00s&lt;span class="o"&gt;)&lt;/span&gt;
PASS
ok      github.com/drpaneas/checkfile/pkg/utils &lt;span class="o"&gt;(&lt;/span&gt;cached&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, see the coverage. Go into the package and run &lt;code&gt;cover&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; cover
PASS
coverage: 77.8% of statements
ok      github.com/drpaneas/checkfile/pkg/utils 0.293s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PS: You need to have this snippet into your &lt;code&gt;~/.bashrc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Go coverage trick&lt;/span&gt;
cover &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;t&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/tmp/go-cover.&lt;/span&gt;&lt;span class="nv"&gt;$$&lt;/span&gt;&lt;span class="s2"&gt;.tmp"&lt;/span&gt;
    go &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;-coverprofile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$t&lt;/span&gt; &lt;span class="nv"&gt;$@&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; go tool cover &lt;span class="nt"&gt;-html&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$t&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;unlink&lt;/span&gt; &lt;span class="nv"&gt;$t&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's enhance the testing coverage, by adding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;"Returns false when provided path is empty"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the tests again and the coverage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;test&lt;/span&gt; ./...

&lt;span class="nv"&gt;$ &lt;/span&gt;cover ./pkg/utils
ok      github.com/drpaneas/checkfile/pkg/utils 0.232s  coverage: 88.9% of statements
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the tests for the other function as well:&lt;/p&gt;

&lt;p&gt;The variables first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;existingFile&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"./testdata/a-file-that-exists"&lt;/span&gt;
    &lt;span class="n"&gt;nonExistingFile&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"./testdata/a-file-that-doesn-not-exist"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The test code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;"Returns true when given file exists"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;existingFile&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;"Returns false when given file does not exist"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;nonExistingFile&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;"Returns false when provided path is empty"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And create the appropriate file for testing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;pkg/utils/testdata/a-file-that-exists
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the tests (they should all pass):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;go &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; ./...?       github.com/drpaneas/checkfile   &lt;span class="o"&gt;[&lt;/span&gt;no &lt;span class="nb"&gt;test &lt;/span&gt;files]
&lt;span class="o"&gt;===&lt;/span&gt; RUN   TestFolderExists
&lt;span class="o"&gt;===&lt;/span&gt; RUN   TestFolderExists/Returns_true_when_given_folder_exists
&lt;span class="o"&gt;===&lt;/span&gt; RUN   TestFolderExists/Returns_false_when_given_folder_does_not_exist
&lt;span class="o"&gt;===&lt;/span&gt; RUN   TestFolderExists/Returns_false_when_provided_path_is_empty
&lt;span class="nt"&gt;---&lt;/span&gt; PASS: TestFolderExists &lt;span class="o"&gt;(&lt;/span&gt;0.00s&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nt"&gt;---&lt;/span&gt; PASS: TestFolderExists/Returns_true_when_given_folder_exists &lt;span class="o"&gt;(&lt;/span&gt;0.00s&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nt"&gt;---&lt;/span&gt; PASS: TestFolderExists/Returns_false_when_given_folder_does_not_exist &lt;span class="o"&gt;(&lt;/span&gt;0.00s&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nt"&gt;---&lt;/span&gt; PASS: TestFolderExists/Returns_false_when_provided_path_is_empty &lt;span class="o"&gt;(&lt;/span&gt;0.00s&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;===&lt;/span&gt; RUN   TestFileExists
&lt;span class="o"&gt;===&lt;/span&gt; RUN   TestFileExists/Returns_true_when_given_file_exists
&lt;span class="o"&gt;===&lt;/span&gt; RUN   TestFileExists/Returns_false_when_given_file_does_not_exist
&lt;span class="o"&gt;===&lt;/span&gt; RUN   TestFileExists/Returns_false_when_provided_path_is_empty
&lt;span class="nt"&gt;---&lt;/span&gt; PASS: TestFileExists &lt;span class="o"&gt;(&lt;/span&gt;0.00s&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nt"&gt;---&lt;/span&gt; PASS: TestFileExists/Returns_true_when_given_file_exists &lt;span class="o"&gt;(&lt;/span&gt;0.00s&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nt"&gt;---&lt;/span&gt; PASS: TestFileExists/Returns_false_when_given_file_does_not_exist &lt;span class="o"&gt;(&lt;/span&gt;0.00s&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nt"&gt;---&lt;/span&gt; PASS: TestFileExists/Returns_false_when_provided_path_is_empty &lt;span class="o"&gt;(&lt;/span&gt;0.00s&lt;span class="o"&gt;)&lt;/span&gt;
PASS
ok      github.com/drpaneas/checkfile/pkg/utils 0.301s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the testing coverage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cover ./pkg/utils
ok      github.com/drpaneas/checkfile/pkg/utils 0.268s  coverage: 100.0% of statements
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although we already hit the 100% testing coverage, I would like to add another test-case.&lt;/p&gt;

&lt;p&gt;Add these two code block respectively:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// TestFolderExists()&lt;/span&gt;
&lt;span class="c"&gt;// ...&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;"Returns false when provided path is not a directory"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;existingFile&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// TestFileExists&lt;/span&gt;
&lt;span class="c"&gt;// ...&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;"Returns false when provided path is not a file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;existingFolder&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;... and that's it!&lt;br&gt;
Run again the tests to verify everything works and we are good to go.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;test&lt;/span&gt; ./...
?       github.com/drpaneas/checkfile   &lt;span class="o"&gt;[&lt;/span&gt;no &lt;span class="nb"&gt;test &lt;/span&gt;files]
ok      github.com/drpaneas/checkfile/pkg/utils 0.332s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Test without testdata
&lt;/h2&gt;

&lt;p&gt;Ok now let's do the same without the actual testdata.&lt;br&gt;
To unit-test your function you need to replace something it uses with something "virtualised". &lt;br&gt;
Exactly how to do that is an open question.&lt;br&gt;
Right now, a work is being done on &lt;a href="https://go.googlesource.com/proposal/+/master/design/draft-iofs.md"&gt;bringing filesystem virtualisation&lt;/a&gt; right into the Go standard library, but while it's not there yet, there's a 3rd-party package which has been doing that for ages, — for instance, github.com/spf13/afero.&lt;/p&gt;

&lt;p&gt;First let's remove the actual real data, and see the tests fail:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; ./pkg/utils/testdata
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So now the tests are failing obviously:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;test&lt;/span&gt; ./...
?       github.com/drpaneas/checkfile   &lt;span class="o"&gt;[&lt;/span&gt;no &lt;span class="nb"&gt;test &lt;/span&gt;files]
&lt;span class="nt"&gt;---&lt;/span&gt; FAIL: TestFolderExists &lt;span class="o"&gt;(&lt;/span&gt;0.00s&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nt"&gt;---&lt;/span&gt; FAIL: TestFolderExists/Returns_true_when_given_folder_exists &lt;span class="o"&gt;(&lt;/span&gt;0.00s&lt;span class="o"&gt;)&lt;/span&gt;
        filesystem_test.go:47: FolderExists&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;, want &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;span class="nt"&gt;---&lt;/span&gt; FAIL: TestFileExists &lt;span class="o"&gt;(&lt;/span&gt;0.00s&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nt"&gt;---&lt;/span&gt; FAIL: TestFileExists/Returns_true_when_given_file_exists &lt;span class="o"&gt;(&lt;/span&gt;0.00s&lt;span class="o"&gt;)&lt;/span&gt;
        filesystem_test.go:86: FileExists&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;, want &lt;span class="nb"&gt;true
&lt;/span&gt;FAIL
FAIL    github.com/drpaneas/checkfile/pkg/utils 0.404s
FAIL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To do that we will use &lt;a href="https://github.com/spf13/afero"&gt;Afero&lt;/a&gt;.&lt;br&gt;
Writing a unit test for filesystem checking is not trivial. You should NOT create a real file on the system, because then your test will depend on the I/O of the file system itself. &lt;/p&gt;

&lt;p&gt;Let's modify our code to use Afero for &lt;strong&gt;both implementation and test&lt;/strong&gt;.&lt;br&gt;
So for the &lt;code&gt;filesystem.go&lt;/code&gt; just add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Making the global, sharing the memory filesystem&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;FS&lt;/span&gt;  &lt;span class="n"&gt;afero&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fs&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;afero&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewMemMapFs&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;AFS&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;afero&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Afero&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;afero&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Afero&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Fs&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;FS&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and replace the &lt;code&gt;os.Stat&lt;/code&gt; to &lt;code&gt;AFS.Stat&lt;/code&gt;. That's all.&lt;br&gt;
For the &lt;code&gt;filesystem_test.go&lt;/code&gt; just add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// create test files and directories&lt;/span&gt;
    &lt;span class="n"&gt;AFS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MkdirAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;existingFolder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0755&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;afero&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AFS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;existingFile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test file"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="m"&gt;0755&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the tests and they should pass:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;test&lt;/span&gt; ./... &lt;span class="nt"&gt;-v&lt;/span&gt;
?       github.com/drpaneas/checkfile   &lt;span class="o"&gt;[&lt;/span&gt;no &lt;span class="nb"&gt;test &lt;/span&gt;files]
&lt;span class="o"&gt;===&lt;/span&gt; RUN   TestFolderExists
&lt;span class="o"&gt;===&lt;/span&gt; RUN   TestFolderExists/Returns_true_when_given_folder_exists
&lt;span class="o"&gt;===&lt;/span&gt; RUN   TestFolderExists/Returns_false_when_given_folder_does_not_exist
&lt;span class="o"&gt;===&lt;/span&gt; RUN   TestFolderExists/Returns_false_when_provided_path_is_empty
&lt;span class="o"&gt;===&lt;/span&gt; RUN   TestFolderExists/Returns_false_when_provided_path_is_not_a_directory
&lt;span class="nt"&gt;---&lt;/span&gt; PASS: TestFolderExists &lt;span class="o"&gt;(&lt;/span&gt;0.00s&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nt"&gt;---&lt;/span&gt; PASS: TestFolderExists/Returns_true_when_given_folder_exists &lt;span class="o"&gt;(&lt;/span&gt;0.00s&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nt"&gt;---&lt;/span&gt; PASS: TestFolderExists/Returns_false_when_given_folder_does_not_exist &lt;span class="o"&gt;(&lt;/span&gt;0.00s&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nt"&gt;---&lt;/span&gt; PASS: TestFolderExists/Returns_false_when_provided_path_is_empty &lt;span class="o"&gt;(&lt;/span&gt;0.00s&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nt"&gt;---&lt;/span&gt; PASS: TestFolderExists/Returns_false_when_provided_path_is_not_a_directory &lt;span class="o"&gt;(&lt;/span&gt;0.00s&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;===&lt;/span&gt; RUN   TestFileExists
&lt;span class="o"&gt;===&lt;/span&gt; RUN   TestFileExists/Returns_true_when_given_file_exists
&lt;span class="o"&gt;===&lt;/span&gt; RUN   TestFileExists/Returns_false_when_given_file_does_not_exist
&lt;span class="o"&gt;===&lt;/span&gt; RUN   TestFileExists/Returns_false_when_provided_path_is_empty
&lt;span class="o"&gt;===&lt;/span&gt; RUN   TestFileExists/Returns_false_when_provided_path_is_not_a_file
&lt;span class="nt"&gt;---&lt;/span&gt; PASS: TestFileExists &lt;span class="o"&gt;(&lt;/span&gt;0.00s&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nt"&gt;---&lt;/span&gt; PASS: TestFileExists/Returns_true_when_given_file_exists &lt;span class="o"&gt;(&lt;/span&gt;0.00s&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nt"&gt;---&lt;/span&gt; PASS: TestFileExists/Returns_false_when_given_file_does_not_exist &lt;span class="o"&gt;(&lt;/span&gt;0.00s&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nt"&gt;---&lt;/span&gt; PASS: TestFileExists/Returns_false_when_provided_path_is_empty &lt;span class="o"&gt;(&lt;/span&gt;0.00s&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nt"&gt;---&lt;/span&gt; PASS: TestFileExists/Returns_false_when_provided_path_is_not_a_file &lt;span class="o"&gt;(&lt;/span&gt;0.00s&lt;span class="o"&gt;)&lt;/span&gt;
PASS
ok      github.com/drpaneas/checkfile/pkg/utils 0.349s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice we have no &lt;em&gt;testdata&lt;/em&gt; any more.&lt;br&gt;
Basically, &lt;code&gt;Afero&lt;/code&gt; allows you to not use &lt;code&gt;os&lt;/code&gt; directly but write all your code in a way so that instead of the &lt;code&gt;os&lt;/code&gt; package it calls methods on an instance of a type implementing particular interface: in the production code that object is a thin shim for the &lt;code&gt;os&lt;/code&gt; package, and in the testing code it's replaced by whatever you wish; &lt;code&gt;afero&lt;/code&gt; has a readily-available in-memory FS backend to do this.&lt;/p&gt;

&lt;p&gt;To sum up, although it's a good idea to do this, there might be cases where Afero fails to offer you this isolation.&lt;br&gt;
For example if you try to do anything on top of the basic filesystem usage, then Afero might not be enough.&lt;br&gt;
For example, if you try to extract, zip or compress a fail, you will see that those functions are not compatible with Afero, thus you will have either to send a PR to afero or suffer by creating lot's of extra code for achieving that.&lt;/p&gt;

</description>
      <category>go</category>
      <category>afero</category>
      <category>testing</category>
      <category>mocking</category>
    </item>
  </channel>
</rss>
