|
1 | | -# gl-dotnet-test-integration |
2 | | -[.NET Core 1.0] Library to help implement integration testing. |
| 1 | +# Testavior |
| 2 | +*Testavior* is a set of [NuGet libraries]() to help you develop **Behavior** Tests for **ASP.NET Core**. |
3 | 3 |
|
4 | | -Coming soon ! |
| 4 | +>Behavior Tests are a way of testing your application features applying different types of behaviors to cover a **functional scenario**. |
| 5 | +
|
| 6 | +It provides a simple and efficient approach to write automated tests for your ASP.NET Core application. |
| 7 | +For more information about *Behavior Testing* with ASP.NET Core, please take a look here http://geeklearning.io/a-different-approach-to-test-your-asp-net-core-application |
| 8 | + |
| 9 | +### Features |
| 10 | +*Testavior* provides 2 libraries: |
| 11 | +* **Configuration**: Helps you configure your application to easily integrate behavior tests for your scenarios. |
| 12 | +* **Integration**: Provides a featured and highly configurable test environment for your behavior tests: |
| 13 | + * Configured Test WebHost |
| 14 | + * Configured authentication context |
| 15 | + * Test authentication middleware |
| 16 | + * Configurable test identity |
| 17 | + * Identity claims helper |
| 18 | + * Configured Entity Framework Core context using SQLite provider |
| 19 | + * Serialization helper to handle URL encoded content |
| 20 | + * Set of HTTP tools to handle *CSRF* protection (very useful to test edition scenarios) |
| 21 | + * Assertion helper |
| 22 | + |
| 23 | +### Installation |
| 24 | +On your ASP.NET Core project |
| 25 | +* Install the **GeekLearning.SceneTest.Configuration** nuget package |
| 26 | + ``` |
| 27 | + > dotnet add package GeekLearning.Testavior.Configuration |
| 28 | + ``` |
| 29 | + |
| 30 | +On your .NET Core Unit Test project |
| 31 | +* Install the **GeekLearning.SceneTest** nuget package |
| 32 | + ``` |
| 33 | + > dotnet add package GeekLearning.Testavior |
| 34 | + ``` |
| 35 | +* Add your ASP.NET Core web project as a project reference |
| 36 | +### Configuration |
| 37 | +The Test environment provided by *SceneTest* is based on a **Startup Configuration Service** that let you separate the **Production** environment configuration from the **Test** environment configuration. |
| 38 | +This configuration service is represented by a contract **IStartupConfigurationService** which define 3 methods: *Configure, ConfigureEnvironment, ConfigureService* that have to be called within the **Startup Routine** to inject environment dependent configuration. |
| 39 | + |
| 40 | +1 - In your **ASP.NET Core** project: |
| 41 | +* Add a *StartupConfigurationService* class (change name if you wish) to your web project. |
| 42 | +* Implement the **IStartupConfigurationService** interface (optionally, inherit from *DefaultStartupConfigurationService* to use the default empty implementation) |
| 43 | +* Implement the configuration specific to the Production environment and which must not be executed in the Test environment: |
| 44 | + * *ConfigureServices*: implement the configuration options that are specific to the Production environment |
| 45 | + * *Configure*: implement the *middleware* configuration specific to the Production environment |
| 46 | + * *ConfigureEnvironment*: implement what has to be executed before anything |
| 47 | + |
| 48 | + Sample: |
| 49 | + ```csharp |
| 50 | + public class StartupConfigurationService : DefaultStartupConfigurationService |
| 51 | +{ |
| 52 | + public override void ConfigureServices(IServiceCollection services, IConfigurationRoot configuration) |
| 53 | + { |
| 54 | + base.ConfigureServices(services, configuration); |
| 55 | + |
| 56 | + var connection = "CONNECTION_STRING"; |
| 57 | + |
| 58 | + services.AddDbContext<Data.BloggingContext>(options => |
| 59 | + options.UseSqlServer(connection)); |
| 60 | + } |
| 61 | +} |
| 62 | + ``` |
| 63 | + |
| 64 | + 2 - In your **Program** class: |
| 65 | + Inject your *StartupConfigurationService* by calling the **ConfigureStartup** method on your **WebHostBuilder**: |
| 66 | + ```csharp |
| 67 | + new WebHostBuilder() |
| 68 | + ... |
| 69 | + .UseStartup<Startup>() |
| 70 | + .ConfigureStartup<StartupConfigurationService>() |
| 71 | + ``` |
| 72 | + |
| 73 | + 3 - In your **Startup** class: |
| 74 | + * Inject the *IStartupConfigurationService* interface into the Startup class |
| 75 | + * Call the *ConfigureEnvironment* method at the end of the Startup constructor |
| 76 | + * Call the *ConfigureServices* method at the end of the original Startup ConfigureServices method |
| 77 | + * Call the *Configure* method at the beginning of the original Startup Configure method |
| 78 | + |
| 79 | + Sample: |
| 80 | + ```csharp |
| 81 | +public class Startup |
| 82 | +{ |
| 83 | + private IStartupConfigurationService externalStartupConfiguration; |
| 84 | + |
| 85 | + public Startup(IHostingEnvironment env, IStartupConfigurationService externalStartupConfiguration = null) |
| 86 | + { |
| 87 | + this.externalStartupConfiguration = externalStartupConfiguration; |
| 88 | + this.externalStartupConfiguration.ConfigureEnvironment(env); |
| 89 | + } |
| 90 | + |
| 91 | + public void ConfigureServices(IServiceCollection services) |
| 92 | + { |
| 93 | + services.AddMvc() |
| 94 | + |
| 95 | + // Pass configuration (IConfigurationRoot) to the configuration service if needed |
| 96 | + this.externalStartupConfiguration.ConfigureServices(services, null); |
| 97 | + } |
| 98 | + |
| 99 | + public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) |
| 100 | + { |
| 101 | + this.externalStartupConfiguration.Configure(app, env, loggerFactory); |
| 102 | + |
| 103 | + app.UseMvc(); |
| 104 | + } |
| 105 | +} |
| 106 | +``` |
| 107 | + |
| 108 | + |
| 109 | +### Writing Tests |
| 110 | +A specific *IStartupConfigurationService* is required for the **Test** environment if you want to implement **Test Specific** configuration. |
| 111 | +*Testavior* comes with a test specific *IStartupConfigurationService* implementation: **TestStartupConfigurationService** which provide a **Test Environment** full of useful features (see **Features** section). |
| 112 | +Of course you can implement your own *Test StartupConfigurationService* (by using the onboard TestStartupConfigurationService or not). |
| 113 | + |
| 114 | +To create a *Test Environment*, just instanciate the **TestEnvironment** class by passing it your ASP.NET Core application *Startup*, your *IStartupConfigurationService* implementation and the type of your EF Core ObjectContext |
| 115 | +```csharp |
| 116 | +var testEnvironment = new TestEnvironment<Startup, TestStartupConfigurationService<[EF_DB_CONTEXT]>>( |
| 117 | + Path.Combine(System.AppContext.BaseDirectory, @"[PATH_TO_WEB_APP]")); |
| 118 | +``` |
| 119 | + |
| 120 | +#### API Test |
| 121 | +Write your API test by just sending web requests using the *Test Environment*: |
| 122 | +```csharp |
| 123 | +var response = testEnvironment.Client.GetAsync("/api/data").Result; |
| 124 | +response.EnsureSuccessStatusCode(); |
| 125 | + |
| 126 | +// Test result content |
| 127 | +var result = JsonConvert.DeserializeObject<Data[]>(response.Content.ReadAsStringAsync().Result); |
| 128 | + |
| 129 | +Assert.AreEqual("data", result.Data); |
| 130 | +... |
| 131 | +``` |
| 132 | + |
| 133 | +#### MVC Test |
| 134 | +Write a MVC test is almost as easy as testing an API except that you might want to test the **Model** returned by the server and not the **View**. |
| 135 | +To do that, *Testavior* provides a **ViewModelRepository** that will intercept and store the view's models returned by the server. |
| 136 | + |
| 137 | +You can access to the this repository using the ASP.NET Core dependency injection mechanism: |
| 138 | + |
| 139 | +```csharp |
| 140 | +[TestMethod] |
| 141 | +public void Mvc_GetBlogsShouldBeOk() |
| 142 | +{ |
| 143 | + base.TestEnvironment.Client.GetAsync("/").Result.EnsureSuccessStatusCode(); |
| 144 | + |
| 145 | + var viewModel = base.TestEnvironment |
| 146 | + .ServiceProvider |
| 147 | + .GetRequiredService<ViewModelRepository>() |
| 148 | + .Get<[VIEWMODEL_TYPE]>(); |
| 149 | + |
| 150 | + Assert.AreEqual("data", viewModel.Data); |
| 151 | +} |
| 152 | +``` |
| 153 | + |
| 154 | +And feel free to take a look at the [Samples](https://github.com/geeklearningio/gl-dotnet-test-integration/tree/develop/sample) section ;) |
| 155 | + |
| 156 | +Happy testing ! :) |
0 commit comments