4

I'm trying to write a SpecFlow test where I test what happens when my application reads a certain structure of folders and files. I want to include these folders and files in my project so the tests don't just run on my own computer.

For example, I have two folders in my Specs project. One called 'SimpleTestModel' and the other called 'ComplexTestModel'. How can I reference these folders in my SpecFlow tests?

David
  • 403
  • 5
  • 14

1 Answers1

5

You want a Test Fixture.

From Wikipedia:

In software testing, a test fixture is a fixed state of the software under test used as a baseline for running tests; also known as the test context. It may also refer to the actions performed in order to bring the system into such a state.

Examples of fixtures:

  • Loading a database with a specific, known set of data
  • Erasing a hard disk and installing a known clean operating system installation
  • Copying a specific known set of files
  • Preparation of input data and set-up/creation of fake or mock objects

Software used to systematically run reproducible tests on a piece of software under test is known as a test harness; part of its job is to set up suitable test fixtures.

For your specific problem:

  1. Create a Fixtures directory in your SpecFlow test project. Inside that create any numbers of sub directories based on your tests to set up the directory and file structures that you need.

  2. Add an <appSettings> in App.config entry define the root folder for all your test fixtures

    <configuration>
      ...
      <appSettings>
        <!-- Path relative to the build output directory -->
        <add name="FixturesRootDirectory" value="..\..\Fixtures" />
      </appSettings>
      ...
    </configuration>
    
  3. In a [BeforeScenario] hook, set the absolute path to the fixtures directory on the current scenario context (reference: How do I get the path of the assembly the code is in?)

    using System.Configuration;
    using System.IO;
    using TechTalk.SpecFlow;
    
    namespace Foo
    {
        [Binding]
        public class CommonHooks
        {
            [BeforeScenario]
            public void BeforeScenario()
            {
                InitFixturesPath();
            }
    
            private void InitFixturesPath()
            {
                if (ScenarioContext.Current.ContainsKey("FixturesPath"))
                    return;
    
                string codeBase = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase)
                                + Path.DirectorySeparatorChar
                                + ConfigurationManager.AppSettings["FixturesRootDirectory"];
                UriBuilder uri = new UriBuilder(codeBase);
                string path = Uri.UnescapeDataString(uri.Path);
    
                ScenarioContext.Current.Set<string>("FixturesPath", Path.GetDirectoryName(path));
            }
        }
    }
    
  4. Now you can use ScenarioContext.Current.Get<string>("FixturesPath") to get the root directory for all of your fixtures. You could even write your own Fixtures helper class:

    public static class FixturesHelper
    {
        public static string Path { get; set; }
    
        // other methods and properties making it easier to use fixtures
    }
    
Community
  • 1
  • 1
Greg Burghardt
  • 17,900
  • 9
  • 49
  • 92
  • +1. This will work, but might be a bit of overkill. If the tests are MSTest then you can simply add a partial class with the same name as the generated test and use the `[DeploymentItem]` attribute to deploy files/folders for those tests. Similar options might exist for NUnit and XUnit. Nice idea though. – Sam Holder Jan 22 '15 at 14:42
  • I tried this solution, but I can't seem to get it to work. The 'codeBase' variable points to a DLL file, like so: "file:///C:/PancakesDevelopment/Product Builder/ProductBuilder/ProductBuilder.Specs/bin/Release/ProductBuilder.Specs.DLL\\Fixtures" which doesn't seem right. Unless I'm misunderstanding or doing something wrong. – David Jan 22 '15 at 16:14
  • Ah, that's right. I need some way to get the base directory of the DLL -- the equivalent of `dirname /some/file.txt` in Bash... I'll do some searching and update my answer. – Greg Burghardt Jan 22 '15 at 17:10
  • Answer updated with the fix. I also had to update the App.config setting, so please take note of that. – Greg Burghardt Jan 22 '15 at 17:17