PlayNicely.Projects 1.1.2

There is a newer prerelease version of this package available.
See the version list below for details.
dotnet add package PlayNicely.Projects --version 1.1.2                
NuGet\Install-Package PlayNicely.Projects -Version 1.1.2                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="PlayNicely.Projects" Version="1.1.2" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add PlayNicely.Projects --version 1.1.2                
#r "nuget: PlayNicely.Projects, 1.1.2"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install PlayNicely.Projects as a Cake Addin
#addin nuget:?package=PlayNicely.Projects&version=1.1.2

// Install PlayNicely.Projects as a Cake Tool
#tool nuget:?package=PlayNicely.Projects&version=1.1.2                

Play Nicely - Projects

Play Nicely Projects supports the definition and packaging (for reading or writing) of MSBuild Projects. These projects can be used to release test NuGet tool projects that you may be developing. This package provides foundation artefacts for tool project testing, however, the actual test execution code and supporting BDD extensions are developed separately, in these projects.

This package, and others, are in use in these tools:

Getting Started

This base package supports the definition of a TestCaseProject via a virtual FileSystem interface. This interface allows for the definition of directories and files, and also the contents of those files.

The other artefacts support reading or writing of a TestCaseProject from/to media. At this time, the project supports reading from .NET assembly resources and writing to the physical file system. Implement concrete versions of IProjectPackageReader and IProjectPackageWriter if you have a specific media that is not currently supported.

Defining Projects

The TestCaseProject class represents a virtual project, you can define a FileSystem by adding directories and files using its fluent interface. You can also specify which file is the ProjectFile from the same file system. Once defined the TestCaseProject doesn't do much on its own, but when combined with PlayNicely.Executor, or other dependent packages, it can have commands executed against it and any output collected for assertions.

var testCaseProject = new TestCaseProject("my-project");
var projectFile = testCaseProject.Root.AddDirectory("project1")
                                      .AddFile("proj.csproj");

testCaseProject.ProjectFile = projectFile;

using(var writer = new StreamWriter(projectFile.OpenWriteStream()))
{
    writer.WriteLine("<Project Sdk=\"Microsoft.NET.Sdk\">");
    writer.WriteLine("  <PropertyGroup>");
    writer.WriteLine("    <TargetFramework>netstandard2.0</TargetFramework>");
    writer.WriteLine("  </PropertyGroup>");
    writer.WriteLine("</Project>");
}

Using Resource (resx) files

Building test case projects in code is fine, but it would be helpful if we could define them declaritively as well. The base package supports this by defining projects in resx files and loading them into a TestCaseProject at runtime.

You would typically use this concept within the IDE, see next section, but you don't have to, you can declare the project using raw XML within a resx file.

To load a TestProject from a resource in an assembly, you use the ResourceSetPackageReader class and pass it to the TestCaseProject.LoadFromAsync method. The constructor requires a ResourceSet, or you can use one of the static Create methods. If you have a .resx file with a generated class, the easiest way to load the resource into a TestCaseProject is like this:

// Resx file is called Project1.resx with generation _on_
using var reader = ResourceSetPackageReader.Create<Project1>();
var testCaseProject = new TestCaseProject("Project1");

await testCaseProject.LoadFromAsync(reader);
Example

This example defines a TestCaseProject within a resx file. Using item keys and values (for the file content).

If you want a TestCaseProject with the following structure...

solution-dir
|-- Project1
|   |-- Project1.csproj
|   |-- Program.cs
|
|-- Project2
|   |-- Project2.csproj
|   |-- Program.cs
|   |-- Consts.cs
|
|-- my-solution.sln

The resx file should have the following resources defined (note the item keys represent paths), and also the special ProjectFile key, the value of which is the path to the project file. If this key is present it sets the TestCaseProject.ProjectFile property to the file at that path.

<?xml version="1.0" encoding="utf-8"?>
<root>
  
  <data name="ProjectFile" xml:space="preserve">
    <value>my-solution.sln</value>
  </data>
  <data name="my-solution.sln" xml:space="preserve">
    <value>...Excluded for bereveity...</value>
  </data>

  <data name="Project1/Project1.csproj" xml:space="preserve">
    <value>
&lt;Project Sdk="Microsoft.NET.Sdk"&gt;
  &lt;PropertyGroup&gt;
    &lt;TargetFramework&gt;net6.0&lt;/TargetFramework&gt;
  &lt;/PropertyGroup&gt;
&lt;/Project&gt;
    </value>
  </data>
  <data name="Project1/Program.cs" xml:space="preserve">
    <value>
using System;

namespace Project1
{
    public static class Program
    {
        public static int Main(params string[] args)
        {
            Console.WriteLine("Project1");

            return 0;
        }
    }
}
    </value>
  </data>

  <data name="Project2/Project2.csproj" xml:space="preserve">
    <value>
&lt;Project Sdk="Microsoft.NET.Sdk"&gt;
  &lt;PropertyGroup&gt;
    &lt;TargetFramework&gt;net6.0&lt;/TargetFramework&gt;
  &lt;/PropertyGroup&gt;
&lt;/Project&gt;
    </value>
  </data>
  <data name="Project2/Program.cs" xml:space="preserve">
    <value>
using System;

namespace Project1
{
    public static class Program
    {
        public static int Main(params string[] args)
        {
            Console.WriteLine("Project2: {0}", Consts.Version);

            return 0;
        }
    }
}
    </value>
  </data>
  <data name="Project2/Consts.cs" xml:space="preserve">
    <value>
using System;

namespace Project1
{
    public static class Consts
    {
        public const string Version = "1.2.3";
    }
}
    </value>
  </data>
</root>

Using the IDE

Ok, so defining test case projects in code isn't ideal, neither is creating raw resx files, really we want to use a familiar tool, i.e. the IDE. Rather than specify file content using raw strings, as in the example above, we can define projects in Visual Studio as normal, Add Project..., New Item..., etc., and then reference them in the resx file for packaging.

Our recomended setup for tools projects that require test cases, is to create a solution structure like this.

solution-dir
|-- Project.UnderTest.Specs    # BDD Specifications for your project
|   |-- TestCases.Projects     # Define your test case 'packages' in resx files
|       |-- Project1.resx
|
|-- TestCase.Projects          # Define your test case projects in here using familiar tools.
|   |-- Project1
|       |-- Project1.csproj
|       |-- Program.cs
|
|-- Project.UnderTest          # The package project that needs to be tested before release
|   |-- Project.UnderTest.csproj
|   |-- SomeCode.cs
|
|-- solution.sln

Key points to consider:

  • The Project.UnderTest is the actual payload project of this repository.
  • Project.UnderTest.Specs is a BDD project that tests the capabilities of Project.UnderTest.
    • The Project1.resx resource includes the files from TestCase.Projects/Project1 directory with ResXFileRef items.
  • The TestCase.Projects directory is a space to define the test case projects, within the IDE. You can add new projects, new classes, interfaces, whatever you need in a familiar environment. Be aware, if this is an unhappy path test, that you need to exclude it from the solution build.
<?xml version="1.0" encoding="utf-8"?>
<root>
  
  <data name="Project1/Project1.csproj" type="System.Resources.ResXFileRef, System.Windows.Forms">
    <value>../TestCase.Projects/Project1/Project1.csproj;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
  </data>
  <data name="Project1/Program.cs" type="System.Resources.ResXFileRef, System.Windows.Forms">
    <value>../TestCase.Projects/Project1/Program.cs;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
  </data>
</root>
Example

The best examples, are real uses, you can find them in these dependent projects.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net8.0

    • No dependencies.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on PlayNicely.Projects:

Package Downloads
PlayNicely.Executor

A framework that facilitates testing of Play Nicely functionality. Provides capability to execute programs, in a controlled environment, against test case projects.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.1.3-beta-550 98 10/4/2024
1.1.3-beta-543 112 9/28/2024
1.1.3-beta-535 106 9/28/2024
1.1.3-beta-529 95 9/23/2024
1.1.3-beta-518 111 9/21/2024
1.1.3-beta-511 97 9/20/2024
1.1.3-beta-509 98 9/20/2024
1.1.3-beta-507 98 9/20/2024
1.1.3-beta-505 97 9/19/2024
1.1.3-beta-501 125 9/18/2024
1.1.3-beta-499 107 9/18/2024
1.1.3-beta-496 112 9/18/2024
1.1.2 166 9/17/2024
1.1.2-beta-494 105 9/18/2024
1.1.2-beta-492 115 9/18/2024
1.1.2-beta-487 111 9/17/2024
1.1.1 220 6/1/2024
1.1.1-beta-479 120 9/14/2024
1.1.1-beta-472 114 9/14/2024
1.1.1-beta-465 129 9/7/2024
1.1.1-beta-450 105 7/14/2024
1.1.1-beta-442 102 7/12/2024
1.1.1-beta-432 105 7/11/2024
1.1.1-beta-418 104 6/1/2024
1.1.1-beta-398 110 6/1/2024
1.1.0 124 5/6/2024
1.1.0-beta-393 120 5/31/2024
1.1.0-beta-382 133 5/21/2024
1.1.0-beta-370 130 5/8/2024
1.1.0-beta-355 133 5/7/2024
1.1.0-beta-349 127 5/7/2024
1.1.0-beta-346 127 5/7/2024
1.1.0-beta-340 131 5/7/2024
1.1.0-beta-323 123 5/6/2024
1.0.7 338 4/11/2024
1.0.7-beta-312 128 4/26/2024
1.0.7-beta-299 143 4/14/2024
1.0.7-beta-296 127 4/14/2024
1.0.7-beta-287 121 4/11/2024
1.0.7-beta-282 125 4/11/2024
1.0.7-beta-280 131 4/10/2024
1.0.7-beta-278 124 4/10/2024
1.0.7-beta-276 120 4/10/2024
1.0.7-beta-274 144 4/9/2024
1.0.7-beta-272 134 4/9/2024
1.0.6 170 3/21/2024
1.0.6-beta-266 127 3/21/2024
1.0.6-beta-260 126 3/21/2024
1.0.5 213 3/10/2024
1.0.5-prerelease-20240301-0... 111 3/1/2024
1.0.5-beta-227 131 3/10/2024
1.0.5-beta-221 139 3/9/2024
1.0.5-beta-214 137 3/9/2024
1.0.5-beta-208 133 3/1/2024
1.0.5-beta-206 129 3/1/2024
1.0.4 133 2/29/2024
1.0.4-prerelease-20240229-1... 88 2/29/2024
1.0.4-prerelease-20240228-0... 87 2/28/2024
1.0.4-prerelease-20240226-1... 108 2/26/2024