Merge branch '1.0.0-beta8' into 1.0.0-rc1

pull/664/head
danroth27 2015-11-17 22:15:33 -08:00
commit 97bfe07cca
17 changed files with 455 additions and 14 deletions

View File

@ -2,28 +2,124 @@ Unit Testing
============
By `Steve Smith`_
This content is in progress.
ASP.NET 5 has been designed with testability in mind, so that creating unit tests for your applications is easier than ever before. This article briefly introduces unit tests (and how they differ from other kinds of tests) and demonstrates how to add a test project to your solution and then run unit tests using either the command line or Visual Studio.
In this article:
- `Introduction to Unit Testing`_
- `Creating Test Projects`_
- `Running Tests`_
.. contents:: In this article:
:local:
:depth: 1
`Download sample from GitHub <https://github.com/aspnet/docs/tree/1.0.0-beta8/aspnet/testing/unit-testing/sample>`_.
`Download sample from GitHub <https://github.com/aspnet/docs/tree/master/aspnet/testing/unit-testing/sample>`_.
Introduction to Unit Testing
Getting Started with Testing
----------------------------
About unit testing
Having a suite of automated tests is one of the best ways to ensure a software application does what its authors intended it to do. There are many different kinds of tests for software applications, including :doc:`integration tests <integration-testing>`, web tests, load tests, and many others. At the lowest level are unit tests, which test individual software components or methods. Unit tests should only test code within the developer's control, and should not test infrastructure concerns, like databases, file systems, or network resources. Unit tests may be written using `Test Driven Development (TDD) <http://deviq.com/test-driven-development/>`_, or they can be added to existing code to confirm its correctness. In either case, they should be small, well-named, and fast, since ideally you will want to be able to run hundreds of them before pushing your changes into the project's shared code repository.
.. note:: Developers often struggle with coming up with good names for their test classes and methods. As a starting point, the ASP.NET product team follows `these conventions <https://github.com/aspnet/Home/wiki/Engineering-guidelines#unit-tests-and-functional-tests>`_
When writing unit tests, be careful you don't accidentally introduce dependencies on infrastructure. These tend to make tests slower and more brittle, and thus should be reserved for integration tests. You can avoid these hidden dependencies in your application code by following the `Explicit Dependencies Principle <http://deviq.com/explicit-dependencies-principle/>`_ and using :doc:`/fundamentals/dependency-injection` to request your dependencies from the framework. You can also keep your unit tests in a separate project from your integration tests, and ensure your unit test project doesn't have references to or dependencies on infrastructure packages.
Creating Test Projects
----------------------
Creating test projects using test runners.
A test project is just a class library with references to a test runner and the project being tested (also referred to as the System Under Test or SUT). It's a good idea to organize your test projects in a separate folder from your SUT projects, and the recommended convention for DNX projects is something like this::
global.json
PrimeWeb.sln
src/
PrimeWeb/
project.json
Startup.cs
Services/
PrimeService.cs
test/
PrimeWeb.UnitTests/
project.json
Services/
PrimeService_IsPrimeShould.cs
It is important that there be a folder/directory with the name of the project you are testing (PrimeWeb above), since the file system is used to find your project.
Configuring the Test project.json
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The test project's ``project.json`` file should add dependencies on the test framework being used and the SUT project. For example, to work with the `xUnit test framework <http://xunit.github.io/>`_, you would configure the dependencies as follows:
.. literalinclude:: unit-testing/sample/test/PrimeWeb.UnitTests/project.json
:language: json
:lines: 20-24
:linenos:
:dedent: 2
As other test frameworks release support for DNX, we will link to them here. We are simply using xUnit as one example of the many different testing frameworks that can be plugged into ASP.NET and DNX.
.. note:: Be sure the version numbers match for your project-to-project references.
In addition to adding dependencies, we also want to be able to run the tests using a DNX command. To do so, add the following commands section to ``project.json``:
.. literalinclude:: unit-testing/sample/test/PrimeWeb.UnitTests/project.json
:language: json
:lines: 25-27
:linenos:
:dedent: 2
.. note:: Learn more about :doc:`/dnx/commands` in DNX.
Running Tests
-------------
Running unit tests on the command line and in visual studio
Summary
-------
Summary
Before you can run your tests, you'll need to write some. For this demo, I've created a simple service that checks whether numbers are prime. One of the tests is shown here:
.. literalinclude:: unit-testing/sample/test/PrimeWeb.UnitTests/Services/PrimeService_IsPrimeShould.cs
:language: c#
:lines: 18-27
:linenos:
:dedent: 8
This test will check the values -1, 0, and 1 using the ``IsPrime`` method in each of three separate tests. Each test will pass if ``IsPrime`` returns false, and will otherwise fail.
You can run tests from the command line or using Visual Studio, whichever you prefer.
Visual Studio
^^^^^^^^^^^^^
To run tests in Visual Studio, first open the Test Explorer tab, then build the solution to have it discover all available tests. Once you have done so, you should see all of your tests in the Test Explorer window. Click Run All to run the tests and see the results.
.. image:: unit-testing/_static/test-explorer.png
If you click the icon in the top-left, Visual Studio will run tests after every build, providing immediate feedback as you work on your application.
Command Line
^^^^^^^^^^^^
To run tests from the command line, navigate to your unit test project folder. Next, run::
dnx test
You should see output similar to the following:
.. image:: unit-testing/_static/dnx-test.png
dnx-watch
^^^^^^^^^
You can use the ``dnx-watch`` command to automatically execute a DNX command whenever the contents of the folder change. This can be used to automatically run tests whenever files are saved in the project. Note that it will detect changes to both the SUT project and the test project, even when run from the test project folder.
To use ``dnx-watch``, simply run it and pass it the command argument you would otherwise have passed to ``dnx``. In this case::
dnx-watch test
With dnx-watch running, you can make updates to your tests and/or your application, and upon saving your changes you should see the tests run again, as shown here:
.. image:: unit-testing/_static/dnx-watch.png
One of the major benefits of automated testing is the rapid feedback tests provide, reducing the time between the introduction of a bug and its discovery. With continuously running tests, whether using ``dnx-watch`` or Visual Studio, developers can almost immediately discover when they've introduced behavior that breaks existing expectations about how the application should behave.
.. tip:: View the `sample <https://github.com/aspnet/docs/tree/1.0.0-beta8/aspnet/testing/unit-testing/sample>`_ to see the complete set of tests and service behavior. You can run the web application and navigate to ``/checkprime?5`` to test whether numbers are prime. You can learn more about testing and refactoring this checkprime web behavior in :doc:`integration-testing`.
Additional Resources
--------------------
- :doc:`integration-testing`
- :doc:`/fundamentals/dependency-injection`

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<!--To inherit the global NuGet package sources remove the <clear/> line below -->
<clear />
<add key="api.nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
</configuration>

View File

@ -0,0 +1,42 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.23107.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{41484C4B-94D9-41D1-9848-A169673C01F2}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{FA6149DB-93D1-43DD-8230-676E8EA81C80}"
ProjectSection(SolutionItems) = preProject
global.json = global.json
NuGet.Config = NuGet.Config
EndProjectSection
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "PrimeWeb", "src\PrimeWeb\PrimeWeb.xproj", "{CAB6DEC1-CE2D-4932-B871-B4B8A7D3B06B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{B23C32D2-95DF-4C95-91C6-2EA5591245E1}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "PrimeWeb.UnitTests", "test\PrimeWeb.UnitTests\PrimeWeb.UnitTests.xproj", "{C76340B0-4F99-44FA-8420-0B2AE0CB64BF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CAB6DEC1-CE2D-4932-B871-B4B8A7D3B06B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CAB6DEC1-CE2D-4932-B871-B4B8A7D3B06B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CAB6DEC1-CE2D-4932-B871-B4B8A7D3B06B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CAB6DEC1-CE2D-4932-B871-B4B8A7D3B06B}.Release|Any CPU.Build.0 = Release|Any CPU
{C76340B0-4F99-44FA-8420-0B2AE0CB64BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C76340B0-4F99-44FA-8420-0B2AE0CB64BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C76340B0-4F99-44FA-8420-0B2AE0CB64BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C76340B0-4F99-44FA-8420-0B2AE0CB64BF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{CAB6DEC1-CE2D-4932-B871-B4B8A7D3B06B} = {41484C4B-94D9-41D1-9848-A169673C01F2}
{C76340B0-4F99-44FA-8420-0B2AE0CB64BF} = {B23C32D2-95DF-4C95-91C6-2EA5591245E1}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,6 @@
{
"projects": [ "src", "test" ],
"sdk": {
"version": "1.0.0-beta8"
}
}

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>cab6dec1-ce2d-4932-b871-b4b8a7d3b06b</ProjectGuid>
<RootNamespace>PrimeWeb</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
<DevelopmentServerPort>51214</DevelopmentServerPort>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View File

@ -0,0 +1,23 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("PrimeWeb")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("PrimeWeb")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("cab6dec1-ce2d-4932-b871-b4b8a7d3b06b")]

View File

@ -0,0 +1,23 @@
using System;
namespace PrimeWeb.Services
{
public class PrimeService
{
public bool IsPrime(int candidate)
{
if(candidate < 2)
{
return false;
}
for(int divisor=2; divisor <= Math.Sqrt(candidate); divisor++)
{
if(candidate % divisor == 0)
{
return false;
}
}
return true;
}
}
}

View File

@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.Dnx.Runtime;
using Microsoft.Framework.DependencyInjection;
using PrimeWeb.Services;
namespace PrimeWeb
{
public class Startup
{
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
}
public void Configure(IApplicationBuilder app,
IHostingEnvironment env)
{
// Add the platform handler to the request pipeline.
app.UseIISPlatformHandler();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.Run(async (context) =>
{
if (context.Request.Path.Value.Contains("checkprime"))
{
int numberToCheck;
try
{
numberToCheck = int.Parse(context.Request.QueryString.Value.Replace("?",""));
var primeService = new PrimeService();
if (primeService.IsPrime(numberToCheck))
{
await context.Response.WriteAsync(numberToCheck + " is prime!");
}
else
{
await context.Response.WriteAsync(numberToCheck + " is NOT prime!");
}
}
catch
{
await context.Response.WriteAsync("Pass in a number to check in the form /checkprime?5");
}
}
else
{
await context.Response.WriteAsync("Hello World!");
}
});
}
}
}

View File

@ -0,0 +1,28 @@
{
"webroot": "wwwroot",
"version": "1.0.0",
"dependencies": {
"Microsoft.AspNet.IISPlatformHandler": "1.0.0-beta8",
"Microsoft.AspNet.Server.Kestrel": "1.0.0-beta8",
"Microsoft.AspNet.Diagnostics": "1.0.0-beta8"
},
"commands": {
"web": "Microsoft.AspNet.Server.Kestrel"
},
"frameworks": {
"dnx451": { },
"dnxcore50": { }
},
"exclude": [
"wwwroot",
"node_modules"
],
"publishExclude": [
"**.user",
"**.vspscc"
]
}

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified"/>
</handlers>
<httpPlatform processPath="%DNX_PATH%" arguments="%DNX_ARGS%" stdoutLogEnabled="false" startupTimeLimit="3600"/>
</system.webServer>
</configuration>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>c76340b0-4f99-44fa-8420-0b2ae0cb64bf</ProjectGuid>
<RootNamespace>PrimeWeb.UnitTests</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View File

@ -0,0 +1,23 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("PrimeWeb.UnitTests")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("PrimeWeb.UnitTests")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("c76340b0-4f99-44fa-8420-0b2ae0cb64bf")]

View File

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Xunit;
using PrimeWeb.Services;
namespace PrimeWeb.UnitTests.Services
{
public class PrimeService_IsPrimeShould
{
private readonly PrimeService _primeService;
public PrimeService_IsPrimeShould()
{
_primeService = new PrimeService();
}
[Theory]
[InlineData(-1)]
[InlineData(0)]
[InlineData(1)]
public void ReturnFalseGivenValuesLessThan2(int value)
{
var result = _primeService.IsPrime(value);
Assert.False(result, String.Format("{0} should not be prime", value));
}
[Theory]
[InlineData(2)]
[InlineData(3)]
[InlineData(5)]
[InlineData(7)]
public void ReturnTrueGivenPrimesLessThan10(int value)
{
var result = _primeService.IsPrime(value);
Assert.True(result, String.Format("{0} should be prime", value));
}
[Theory]
[InlineData(4)]
[InlineData(6)]
[InlineData(8)]
[InlineData(9)]
public void ReturnFalseGivenNonPrimesLessThan10(int value)
{
var result = _primeService.IsPrime(value);
Assert.False(result, String.Format("{0} should not be prime", value));
}
}
}

View File

@ -0,0 +1,28 @@
{
"version": "1.0.0-*",
"description": "PrimeWeb.UnitTests Class Library",
"authors": [ "stevesmith (@ardalis)" ],
"tags": [ "" ],
"projectUrl": "",
"licenseUrl": "",
"frameworks": {
"dnx451": { },
"dnxcore50": {
"dependencies": {
"Microsoft.CSharp": "4.0.1-beta-23409",
"System.Collections": "4.0.11-beta-23409",
"System.Linq": "4.0.1-beta-23409",
"System.Runtime": "4.0.21-beta-23409",
"System.Threading": "4.0.11-beta-23409"
}
}
},
"dependencies": {
"PrimeWeb": "1.0.0",
"xunit": "2.1.0",
"xunit.runner.dnx": "2.1.0-beta6-build191"
},
"commands": {
"test": "xunit.runner.dnx"
}
}