Skip to content
This repository has been archived by the owner on Nov 2, 2018. It is now read-only.

Commit

Permalink
Create a test specification package
Browse files Browse the repository at this point in the history
  • Loading branch information
pranavkm committed Oct 30, 2015
1 parent cfd2c5f commit f1c0dbb
Show file tree
Hide file tree
Showing 73 changed files with 1,196 additions and 978 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ nuget.exe
*.ipch
*.sln.ide
project.lock.json
.vs
15 changes: 15 additions & 0 deletions DependencyInjection.sln
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionIt
README.md = README.md
EndProjectSection
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Extensions.DependencyInjection.Specification.Tests", "src\Microsoft.Extensions.DependencyInjection.Specification.Tests\Microsoft.Extensions.DependencyInjection.Specification.Tests.xproj", "{B9395B0F-E8E3-4913-BABF-E71A76F21231}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -61,6 +63,18 @@ Global
{4E959D3B-2E0D-4296-B22C-D428DED294F0}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{4E959D3B-2E0D-4296-B22C-D428DED294F0}.Release|x86.ActiveCfg = Release|Any CPU
{4E959D3B-2E0D-4296-B22C-D428DED294F0}.Release|x86.Build.0 = Release|Any CPU
{B9395B0F-E8E3-4913-BABF-E71A76F21231}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B9395B0F-E8E3-4913-BABF-E71A76F21231}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B9395B0F-E8E3-4913-BABF-E71A76F21231}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{B9395B0F-E8E3-4913-BABF-E71A76F21231}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{B9395B0F-E8E3-4913-BABF-E71A76F21231}.Debug|x86.ActiveCfg = Debug|Any CPU
{B9395B0F-E8E3-4913-BABF-E71A76F21231}.Debug|x86.Build.0 = Debug|Any CPU
{B9395B0F-E8E3-4913-BABF-E71A76F21231}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B9395B0F-E8E3-4913-BABF-E71A76F21231}.Release|Any CPU.Build.0 = Release|Any CPU
{B9395B0F-E8E3-4913-BABF-E71A76F21231}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{B9395B0F-E8E3-4913-BABF-E71A76F21231}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{B9395B0F-E8E3-4913-BABF-E71A76F21231}.Release|x86.ActiveCfg = Release|Any CPU
{B9395B0F-E8E3-4913-BABF-E71A76F21231}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -69,5 +83,6 @@ Global
{07ABDD98-9974-48CB-8265-53D1A8EC9E34} = {D26F6F80-63EE-4081-A814-EF3DBABE24D9}
{20201277-5461-49EF-811B-63ED3CD274EF} = {88B347C1-CCEC-4827-9564-FFF07C9BF7C7}
{4E959D3B-2E0D-4296-B22C-D428DED294F0} = {D26F6F80-63EE-4081-A814-EF3DBABE24D9}
{B9395B0F-E8E3-4913-BABF-E71A76F21231} = {D26F6F80-63EE-4081-A814-EF3DBABE24D9}
EndGlobalSection
EndGlobal
3 changes: 2 additions & 1 deletion NuGetPackageVerifier.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
],
"packages": {
"Microsoft.Extensions.DependencyInjection": { },
"Microsoft.Extensions.DependencyInjection.Abstractions": { }
"Microsoft.Extensions.DependencyInjection.Abstractions": { },
"Microsoft.Extensions.DependencyInjection.Specification.Tests": { },
}
},
"Default": { // Rules to run for packages not listed in any other set.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,285 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.DependencyInjection.Specification.Fakes;
using Xunit;

namespace Microsoft.Extensions.DependencyInjection.Specification
{
public abstract partial class DependencyInjectionSpecificationTests
{
public delegate object CreateInstanceFunc(IServiceProvider provider, Type type, object[] args);

private static object CreateInstanceDirectly(IServiceProvider provider, Type type, object[] args)
{
return ActivatorUtilities.CreateInstance(provider, type, args);
}

private static object CreateInstanceFromFactory(IServiceProvider provider, Type type, object[] args)
{
var factory = ActivatorUtilities.CreateFactory(type, args.Select(a => a.GetType()).ToArray());
return factory(provider, args);
}

private static T CreateInstance<T>(CreateInstanceFunc func, IServiceProvider provider, params object[] args)
{
return (T)func(provider, typeof(T), args);
}

public static IEnumerable<object[]> CreateInstanceFuncs
{
get
{
yield return new[] { (CreateInstanceFunc)CreateInstanceDirectly };
yield return new[] { (CreateInstanceFunc)CreateInstanceFromFactory };
}
}

[Theory]
[MemberData(nameof(CreateInstanceFuncs))]
public void TypeActivatorEnablesYouToCreateAnyTypeWithServicesEvenWhenNotInIocContainer(CreateInstanceFunc createFunc)
{
// Arrange
var serviceCollection = new ServiceCollection()
.AddTransient<IFakeService, FakeService>();
var serviceProvider = CreateServiceProvider(serviceCollection);

var anotherClass = CreateInstance<AnotherClass>(createFunc, serviceProvider);

Assert.NotNull(anotherClass.FakeService);
}

[Theory]
[MemberData(nameof(CreateInstanceFuncs))]
public void TypeActivatorAcceptsAnyNumberOfAdditionalConstructorParametersToProvide(CreateInstanceFunc createFunc)
{
// Arrange
var serviceCollection = new ServiceCollection()
.AddTransient<IFakeService, FakeService>();
var serviceProvider = CreateServiceProvider(serviceCollection);

// Act
var anotherClass = CreateInstance<AnotherClassAcceptingData>(createFunc, serviceProvider, "1", "2");

// Assert
Assert.NotNull(anotherClass.FakeService);
Assert.Equal("1", anotherClass.One);
Assert.Equal("2", anotherClass.Two);
}

[Theory]
[MemberData(nameof(CreateInstanceFuncs))]
public void TypeActivatorWorksWithStaticCtor(CreateInstanceFunc createFunc)
{
// Act
var anotherClass = CreateInstance<ClassWithStaticCtor>(createFunc, provider: null);

// Assert
Assert.NotNull(anotherClass);
}

[Theory]
[MemberData(nameof(CreateInstanceFuncs))]
public void TypeActivatorWorksWithCtorWithOptionalArgs(CreateInstanceFunc createFunc)
{
// Arrange
var provider = new ServiceCollection();
var serviceProvider = CreateServiceProvider(provider);

// Act
var anotherClass = CreateInstance<ClassWithOptionalArgsCtor>(createFunc, serviceProvider);

// Assert
Assert.NotNull(anotherClass);
Assert.Equal("BLARGH", anotherClass.Whatever);
}

[Theory]
[MemberData(nameof(CreateInstanceFuncs))]
public void TypeActivatorCanDisambiguateConstructorsWithUniqueArguments(CreateInstanceFunc createFunc)
{
// Arrange
var serviceCollection = new ServiceCollection()
.AddTransient<IFakeService, FakeService>();
var serviceProvider = CreateServiceProvider(serviceCollection);

// Act
var instance = CreateInstance<ClassWithAmbiguousCtors>(createFunc, serviceProvider, "1", 2);

// Assert
Assert.NotNull(instance);
Assert.NotNull(instance.FakeService);
Assert.Equal("1", instance.Data1);
Assert.Equal(2, instance.Data2);
}

public static IEnumerable<object[]> TypesWithNonPublicConstructorData =>
CreateInstanceFuncs.Zip(
new[] { typeof(ClassWithPrivateCtor), typeof(ClassWithInternalConstructor), typeof(ClassWithProtectedConstructor) },
(a, b) => new object[] { a[0], b });

[Theory]
[MemberData(nameof(TypesWithNonPublicConstructorData))]
public void TypeActivatorRequiresPublicConstructor(CreateInstanceFunc createFunc, Type type)
{
var ex = Assert.Throws<InvalidOperationException>(() =>
createFunc(provider: null, type: type, args: new object[0]));

Assert.Equal($"Unable to locate suitable constructor for type '{type}'. Ensure the type is concrete" +
" and all parameters are accepted by a constructor.", ex.Message);
}

[Theory]
[MemberData(nameof(CreateInstanceFuncs))]
public void TypeActivatorRequiresAllArgumentsCanBeAccepted(CreateInstanceFunc createFunc)
{
// Arrange
var expectedMessage = $"Unable to locate suitable constructor for type '{typeof(AnotherClassAcceptingData)}'." +
" Ensure the type is concrete and all parameters are accepted by a constructor.";
var serviceCollection = new ServiceCollection()
.AddTransient<IFakeService, FakeService>();
var serviceProvider = CreateServiceProvider(serviceCollection);

var ex1 = Assert.Throws<InvalidOperationException>(() =>
CreateInstance<AnotherClassAcceptingData>(createFunc, serviceProvider, "1", "2", "3"));
var ex2 = Assert.Throws<InvalidOperationException>(() =>
CreateInstance<AnotherClassAcceptingData>(createFunc, serviceProvider, 1, 2));

Assert.Equal(expectedMessage, ex1.Message);
Assert.Equal(expectedMessage, ex2.Message);
}

[Theory]
[MemberData(nameof(CreateInstanceFuncs))]
public void TypeActivatorRethrowsOriginalExceptionFromConstructor(CreateInstanceFunc createFunc)
{
// Act
var ex1 = Assert.Throws<Exception>(() =>
CreateInstance<ClassWithThrowingEmptyCtor>(createFunc, provider: null));

var ex2 = Assert.Throws<Exception>(() =>
CreateInstance<ClassWithThrowingCtor>(createFunc, provider: null, args: new[] { new FakeService() }));

// Assert
Assert.Equal(nameof(ClassWithThrowingEmptyCtor), ex1.Message);
Assert.Equal(nameof(ClassWithThrowingCtor), ex2.Message);
}

[Theory]
[InlineData(typeof(string))]
[InlineData(typeof(int))]
public void TypeActivatorCreateFactoryDoesNotAllowForAmbiguousConstructorMatches(Type paramType)
{
// Arrange
var type = typeof(ClassWithAmbiguousCtors);
var expectedMessage = $"Multiple constructors accepting all given argument types have been found in type '{type}'. " +
"There should only be one applicable constructor.";

// Act
var ex = Assert.Throws<InvalidOperationException>(() =>
ActivatorUtilities.CreateFactory(type, new[] { paramType }));

// Assert
Assert.Equal(expectedMessage, ex.Message);
}

[Fact]
public void GetServiceOrCreateInstanceRegisteredServiceTransient()
{
// Reset the count because test order is not guaranteed
lock (CreationCountFakeService.InstanceLock)
{
CreationCountFakeService.InstanceCount = 0;

var serviceCollection = new ServiceCollection()
.AddTransient<IFakeService, FakeService>()
.AddTransient<CreationCountFakeService>();

var serviceProvider = CreateServiceProvider(serviceCollection);

var service = ActivatorUtilities.GetServiceOrCreateInstance<CreationCountFakeService>(serviceProvider);
Assert.NotNull(service);
Assert.Equal(1, service.InstanceId);
Assert.Equal(1, CreationCountFakeService.InstanceCount);

service = ActivatorUtilities.GetServiceOrCreateInstance<CreationCountFakeService>(serviceProvider);
Assert.NotNull(service);
Assert.Equal(2, service.InstanceId);
Assert.Equal(2, CreationCountFakeService.InstanceCount);
}
}

[Fact]
public void GetServiceOrCreateInstanceRegisteredServiceSingleton()
{
lock (CreationCountFakeService.InstanceLock)
{
// Arrange
// Reset the count because test order is not guaranteed
CreationCountFakeService.InstanceCount = 0;

var serviceCollection = new ServiceCollection()
.AddTransient<IFakeService, FakeService>()
.AddSingleton<CreationCountFakeService>();
var serviceProvider = CreateServiceProvider(serviceCollection);

// Act and Assert
var service = ActivatorUtilities.GetServiceOrCreateInstance<CreationCountFakeService>(serviceProvider);
Assert.NotNull(service);
Assert.Equal(1, service.InstanceId);
Assert.Equal(1, CreationCountFakeService.InstanceCount);

service = ActivatorUtilities.GetServiceOrCreateInstance<CreationCountFakeService>(serviceProvider);
Assert.NotNull(service);
Assert.Equal(1, service.InstanceId);
Assert.Equal(1, CreationCountFakeService.InstanceCount);
}
}

[Fact]
public void GetServiceOrCreateInstanceUnregisteredService()
{
lock (CreationCountFakeService.InstanceLock)
{
// Arrange
// Reset the count because test order is not guaranteed
CreationCountFakeService.InstanceCount = 0;

var serviceCollection = new ServiceCollection()
.AddTransient<IFakeService, FakeService>();
var serviceProvider = CreateServiceProvider(serviceCollection);

// Act and Assert
var service = (CreationCountFakeService)ActivatorUtilities.GetServiceOrCreateInstance(
serviceProvider,
typeof(CreationCountFakeService));
Assert.NotNull(service);
Assert.Equal(1, service.InstanceId);
Assert.Equal(1, CreationCountFakeService.InstanceCount);

service = ActivatorUtilities.GetServiceOrCreateInstance<CreationCountFakeService>(serviceProvider);
Assert.NotNull(service);
Assert.Equal(2, service.InstanceId);
Assert.Equal(2, CreationCountFakeService.InstanceCount);
}
}

[Theory]
[MemberData(nameof(CreateInstanceFuncs))]
public void UnRegisteredServiceAsConstructorParameterThrowsException(CreateInstanceFunc createFunc)
{
var serviceCollection = new ServiceCollection()
.AddSingleton<CreationCountFakeService>();
var serviceProvider = CreateServiceProvider(serviceCollection);

var ex = Assert.Throws<InvalidOperationException>(() =>
CreateInstance<CreationCountFakeService>(createFunc, serviceProvider));
Assert.Equal($"Unable to resolve service for type '{typeof(IFakeService)}' while attempting" +
$" to activate '{typeof(CreationCountFakeService)}'.",
ex.Message);
}
}
}
Loading

0 comments on commit f1c0dbb

Please sign in to comment.