Skip to content

ritterim/sandbox

Repository files navigation

Sandbox

Sandbox takes all the work done with the RimDev Automation libraries and encapsulates them in a simple to use abstraction aimed at making integration testing as easy as child's play.

NuGet Version NuGet Download Count

Getting Started

You can install Sandbox via Nuget.org using the Sandbox id.

PM> Install-Package RimDev.Sandbox

This package will download the following core libraries, which can be used.

  • RimDev.Sandbox.Tranform
  • RimDev.Sandbox.IisExpress
  • RimDev.Sandbox.LocalDb

which in turn utilize the RimDev Automation Libraries:

Then all you need to do is create a new Sandbox and register the necessary grains, which is done via extension methods.

var sandbox = new Sandbox
                    .UseIisExpress(pathToSite)
                    .UseTransform()
                    .UseLocalDb();

using (var sb = sandbox.Play() as dynamic) {

  var endpoint = sb.IisExpress.HttpEndpoint as string;
  var database = sb.LocalDb.Instance as LocalDb;
  var webConfig = Path.Combine(sb.IisExpress.WorkingDirectory, "web.config") as string;

  var transform = sb.Transform.Instance as ConfigurationTransformer;

  transform
    .SetSourceFromFile(webConfig)
    .Transform.InsertConnectionString("test", database.ConnectionString);

  transform.Apply(webConfig);

  // Your IisExpress is now configured with a database
  // that we just created!

  // Do some integration testing!

  Assert.IsAwesome(); // TRUE

}

How It Works

Sandbox wants to isolate your integration tests as much as possible so we create a unique sandbox folder under the current user's temp directory. This temp directory will house any file system artifacts generated by the specific grains registered to the sandbox.

Grains are the specific components you will use. They are registered to the Sandbox via extension methods. The name of the grain is registered to the sandbox and then can be accessed later dynamically.

Grain Access (Dynamic)

The sandbox is a dynamic object. This gives you a nice syntax to access registered grains.

var sandbox = new Sandbox().UseLocalDb() as dynamic;
LocalDb database = sandbox.LocalDb as LocalDb;

You can also change the name of the registered grain using the registration method.

var sandbox = new Sandbox().UseLocalDb(name: "Test") as dynamic;
LocalDb database = sandbox.Test as LocalDb;

Additionally, your application may need more than one instance of any grain. The only caveat, is that each new grain must have a different name.

var sandbox = new Sandbox().UseLocalDb(name: "One").UseLocalDb(name:"Two") as dynamic;
LocalDb one = sandbox.One as LocalDb;
LocalDb two = sandbox.Two as LocalDb;

Grain Access (Static)

If you hate the word dynamic then we have you covered. You can still access grains via a simple method call.

var sandbox = new Sandbox().UseLocalDb();
var database = sandbox.Get<LocalDbGrain>("LocalDb");

All In One Sample

The sample below utilizes all the current grains in one use case. The steps below create a working demo.

  1. Create a new Sandbox
  2. Register Transform
  3. Register IisExpress
  4. Register LocalDb
  5. Modify the web.config of the Web App with the connection string
  6. Create tables and data using the database
  7. Make a web request to the new instance
public class MashupTests
{
  public const string Aspx =
  @"
  <%@ Page Language=""C#""%>
  <html>
  <head>
  <title>Hello World!</title>
  </head>
  <body>
  <%
  var connectionString = System.Configuration.ConfigurationManager.ConnectionStrings[""test""].ConnectionString;
  using (var connection = new System.Data.SqlClient.SqlConnection(connectionString)) {
    connection.Open();
    var command = connection.CreateCommand();
    command.CommandText = ""Select PersonID, FirstName, LastName from Persons"";
    using (var reader = command.ExecuteReader()) {
      if (reader.HasRows) {
        while(reader.Read()) {
          Response.Write(""<p>"" + reader.GetInt32(0) + "" "" + reader.GetString(1) + "" "" + reader.GetString(2) + ""</p>"");
        }
      }
      else
      {
        Response.Write(""<p>No rows found.</p>"");
      }
    }
  }
  %>
  </body>
  </html>";

  [Fact]
  public void Can_use_iisexpress_localdb_and_transform()
  {
    var path = CreateTempTestDirectory(Aspx);
    var sandbox =
    new Sandbox()
    .UseTranform()
    .UseIisExpress(path)
    .UseLocalDb();

    using (sandbox.Play())
    {
      var box = sandbox as dynamic;
      var webConfig = Path.Combine(box.IisExpress.WorkingDirectory, "web.config") as string;
      var transform = box.Transform.Instance as ConfigurationTransformer;
      var database = box.LocalDb.Instance as RimDev.Automation.Sql.LocalDb;

      transform
      .SetSourceFromFile(webConfig)
      .Transform.InsertConnectionString("test", database.ConnectionString);

      transform.Apply(webConfig);

      using (var connection = database.OpenConnection())
      {
        var command = connection.CreateCommand();
        command.CommandText =
        "CREATE TABLE Persons (PersonID int,LastName varchar(255),FirstName varchar(255));";
        command.ExecuteNonQuery();
      }

      using (var connection = database.OpenConnection())
      {
        var command = connection.CreateCommand();
        command.CommandText =
        "Insert Into Persons (PersonID, LastName, FirstName) Values (1, 'Test', 'User');";
        command.ExecuteNonQuery();
      }

      var url = string.Format("{0}/index.aspx",box.IisExpress.HttpEndpoint);
      var response = Get(url);

      Assert.Contains("Test", response);
      Assert.Contains("User", response);
      Assert.Contains("1", response);
    }
  }

  private string CreateTempTestDirectory(string content)
  {
    string path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
    if (!Directory.Exists(path))
    Directory.CreateDirectory(path);

    File.WriteAllText(Path.Combine(path, "index.aspx"), content);
    File.WriteAllText(Path.Combine(path, "web.config"), "<?xml version=\"1.0\"?><configuration><system.web><compilation debug=\"true\"/></system.web><connectionStrings/><system.webServer><defaultDocument enabled=\"true\"><files><clear /><add value=\"index.html\" /></files></defaultDocument></system.webServer></configuration>");

    return path;
  }

  private static string Get(string url)
  {
    var request = WebRequest.CreateHttp(url);
    using (var response = request.GetResponse())
    {
      using (var reader = new StreamReader(response.GetResponseStream()))
      {
        return reader.ReadToEnd();
      }
    }
  }
}

Thanks

Thanks to Ritter IM for supporting OSS.

About

An abstraction utilizing RimDev Automation libraries

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •