Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow benchmark classes and methods to be executed using TestDriven.Net #259

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Changed from using [assembly: CustomTestRunner...] to [assembly: Benc…
…hmarkTestRunner...].

Allow ConfigType to be specified using [assembly: BenchmarkTestRunner(typeof(MyConfig))].
  • Loading branch information
jcansdale committed Sep 14, 2016
commit 2103544f8129edb20a40cc9bb3949b57b261d888
4 changes: 2 additions & 2 deletions samples/BenchmarkDotNet.Samples/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Runtime.InteropServices;
using BenchmarkDotNet.Properties;
using BenchmarkDotNet.TestDriven;
using TestDriven.Framework;

[assembly: AssemblyTitle(BenchmarkDotNetInfo.Title + ".Samples")]
[assembly: AssemblyProduct(BenchmarkDotNetInfo.Title + ".Samples")]
Expand All @@ -19,4 +18,5 @@
[assembly: ComVisible(false)]
[assembly: Guid("6f2232a9-0d0c-46cf-b08c-f6e28ab612e3")]

[assembly: CustomTestRunner(typeof(FastAndDirtyBenchmarkTestRunner))]
[assembly: BenchmarkTestRunner(typeof(FastAndDirtyConfig))]
//[assembly: BenchmarkTestRunner(typeof(FastAndDirtyClrAndCoreConfig))]
88 changes: 70 additions & 18 deletions src/BenchmarkDotNet.TestDriven/BenchmarkTestRunner.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Reflection;
using System;
using System.Reflection;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Running;
using BenchmarkDotNet.Reports;
Expand All @@ -7,30 +8,46 @@

namespace BenchmarkDotNet.TestDriven
{
public abstract class BenchmarkTestRunner : ITestRunner
public class BenchmarkTestRunner : ITestRunner
{
public abstract IConfig GetConfig();
Type configType;

public BenchmarkTestRunner()
{
}

public BenchmarkTestRunner(Type configType)
{
this.configType = configType;
}

public TestRunState RunMember(ITestListener testListener, Assembly assembly, MemberInfo member)
{
var summary = run(member);
if (summary == null)
try
{
return TestRunState.NoTests;
}
var summary = run(assembly, member);
if (summary == null)
{
return TestRunState.NoTests;
}

foreach (var benchmark in summary.Benchmarks)
{
var testResult = getTestResult(benchmark);
testListener.TestFinished(testResult);
}
foreach (var benchmark in summary.Benchmarks)
{
var testResult = getTestResult(benchmark);
testListener.TestFinished(testResult);
}

testListener.TestResultsUrl(summary.ResultsDirectoryPath);
testListener.TestResultsUrl(summary.ResultsDirectoryPath);

return TestRunState.Success;
return TestRunState.Success;
}
catch(TestRunnerException e)
{
testListener.WriteLine(e.Message, Category.Warning);
return TestRunState.Error;
}
}


static TestResult getTestResult(Benchmark benchmark)
{
var testResult = new TestResult();
Expand All @@ -51,14 +68,15 @@ static string getTestRunnerName()
return string.Format("BenchmarkDotNet {0}.{1}.{2}", version.Major, version.Minor, version.Build);
}

Summary run(MemberInfo member)
Summary run(Assembly assembly, MemberInfo member)
{
if (member is TypeInfo)
{
var type = (TypeInfo)member;
if (isBenchmarkType(type))
{
return BenchmarkRunner.Run(type.AsType(), GetConfig());
var config = getConfig(assembly);
return BenchmarkRunner.Run(type.AsType(), config);
}
}
else if (member is MethodInfo)
Expand All @@ -67,13 +85,40 @@ Summary run(MemberInfo member)
if (isBenchmarkMethod(method))
{
var type = method.DeclaringType;
return BenchmarkRunner.Run(type, new[] { method }, GetConfig());
var config = getConfig(assembly);
return BenchmarkRunner.Run(type, new[] { method }, config);
}
}

return null;
}

IConfig getConfig(Assembly assembly)
{
var configType = getConfigType(assembly);
try
{
var config = (IConfig)Activator.CreateInstance(configType);
return config;
}
catch(InvalidCastException)
{
throw new TestRunnerException(string.Format("ConfigType `{0}` must implement `{1}`.",
configType.FullName, typeof(IConfig).FullName));
}
}

Type getConfigType(Assembly assembly)
{
if (configType != null)
{
return configType;
}

var attribute = assembly.GetCustomAttribute<BenchmarkTestRunnerAttribute>();
return attribute.ConfigType;
}

static bool isBenchmarkType(TypeInfo type)
{
foreach (var method in type.GetMethods())
Expand Down Expand Up @@ -101,5 +146,12 @@ public TestRunState RunAssembly(ITestListener testListener, Assembly assembly)
{
return TestRunState.NoTests;
}

class TestRunnerException : Exception
{
internal TestRunnerException(string message) : base(message)
{
}
}
}
}
18 changes: 18 additions & 0 deletions src/BenchmarkDotNet.TestDriven/BenchmarkTestRunnerAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;
using TestDriven.Framework;

namespace BenchmarkDotNet.TestDriven
{
public class BenchmarkTestRunnerAttribute : CustomTestRunnerAttribute
{
public BenchmarkTestRunnerAttribute(Type configType) : base(typeof(BenchmarkTestRunner))
{
ConfigType = configType;
}

public Type ConfigType
{
get;
}
}
}
28 changes: 28 additions & 0 deletions src/BenchmarkDotNet.TestDriven/FastAndDirtyClrAndCoreConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Configs;

namespace BenchmarkDotNet.TestDriven
{
// See https://perfdotnet.github.io/BenchmarkDotNet/faq.htm
public class FastAndDirtyClrAndCoreConfig : ManualConfig
{
public FastAndDirtyClrAndCoreConfig()
{
Add(DefaultConfig.Instance);

Add(Job.Clr
.WithLaunchCount(1) // benchmark process will be launched only once
.WithIterationTime(100) // 100ms per iteration
.WithWarmupCount(3) // 3 warmup iteration
.WithTargetCount(3) // 3 target iteration
);

Add(Job.Core
.WithLaunchCount(1) // benchmark process will be launched only once
.WithIterationTime(100) // 100ms per iteration
.WithWarmupCount(3) // 3 warmup iteration
.WithTargetCount(3) // 3 target iteration
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,19 @@

namespace BenchmarkDotNet.TestDriven
{
public class FastAndDirtyBenchmarkTestRunner : BenchmarkTestRunner
// See https://perfdotnet.github.io/BenchmarkDotNet/faq.htm
public class FastAndDirtyConfig : ManualConfig
{
// See https://perfdotnet.github.io/BenchmarkDotNet/faq.htm
public override IConfig GetConfig()
public FastAndDirtyConfig()
{
var config = new ManualConfig();
config.Add(DefaultConfig.Instance);
config.Add(Job.Default
Add(DefaultConfig.Instance);

Add(Job.Default
.WithLaunchCount(1) // benchmark process will be launched only once
.WithIterationTime(100) // 100ms per iteration
.WithWarmupCount(3) // 3 warmup iteration
.WithTargetCount(3) // 3 target iteration
);
return config;
}
}
}
4 changes: 0 additions & 4 deletions src/BenchmarkDotNet.TestDriven/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
using System.Reflection;
using System.Runtime.InteropServices;
using TestDriven.Framework;
using BenchmarkDotNet.TestDriven;

[assembly: CustomTestRunner(typeof(FastAndDirtyBenchmarkTestRunner))]

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ public class BenckmarkTestRunnerTests
[Test]
public void RunMember_NoBenchmarks_NoTests()
{
var benchmarkTestRunner = Substitute.For<BenchmarkTestRunner>();
benchmarkTestRunner.GetConfig().Returns(new SuperQuickConfig());
var benchmarkTestRunner = new BenchmarkTestRunner(typeof(QuickConfig));
var testListener = Substitute.For<ITestListener>();
var targetType = typeof(NoBenchmarks).GetTypeInfo();

Expand All @@ -29,8 +28,7 @@ public void RunMember_NoBenchmarks_NoTests()
[Test]
public void RunMember_SomeBenchmarks_Success2Tests()
{
var benchmarkTestRunner = Substitute.For<BenchmarkTestRunner>();
benchmarkTestRunner.GetConfig().Returns(new SuperQuickConfig());
var benchmarkTestRunner = new BenchmarkTestRunner(typeof(QuickConfig));
var testListener = Substitute.For<ITestListener>();
var targetType = typeof(SomeBenchmarks).GetTypeInfo();

Expand All @@ -43,8 +41,7 @@ public void RunMember_SomeBenchmarks_Success2Tests()
[Test]
public void RunMember_SomeBenchmarks_TestRunnerName()
{
var benchmarkTestRunner = Substitute.For<BenchmarkTestRunner>();
benchmarkTestRunner.GetConfig().Returns(new SuperQuickConfig());
var benchmarkTestRunner = new BenchmarkTestRunner(typeof(QuickConfig));
var testListener = Substitute.For<ITestListener>();
var targetType = typeof(SomeBenchmarks).GetTypeInfo();
var version = typeof(BenchmarkAttribute).GetTypeInfo().Assembly.GetName().Version;
Expand All @@ -58,8 +55,7 @@ public void RunMember_SomeBenchmarks_TestRunnerName()
[Test]
public void RunMember_SomeBenchmarks_TestResultName()
{
var benchmarkTestRunner = Substitute.For<BenchmarkTestRunner>();
benchmarkTestRunner.GetConfig().Returns(new SuperQuickConfig());
var benchmarkTestRunner = new BenchmarkTestRunner(typeof(QuickConfig));
var testListener = Substitute.For<ITestListener>();
var targetType = typeof(SomeBenchmarks).GetTypeInfo();
var method = new Action(new SomeBenchmarks().Benchmark1).GetMethodInfo();
Expand All @@ -73,8 +69,7 @@ public void RunMember_SomeBenchmarks_TestResultName()
[Test]
public void RunMember_SomeBenchmarksBenchmark1_TestResultName()
{
var benchmarkTestRunner = Substitute.For<BenchmarkTestRunner>();
benchmarkTestRunner.GetConfig().Returns(new SuperQuickConfig());
var benchmarkTestRunner = new BenchmarkTestRunner(typeof(QuickConfig));
var testListener = Substitute.For<ITestListener>();
var targetType = typeof(SomeBenchmarks).GetTypeInfo();
var method = new Action(new SomeBenchmarks().Benchmark1).GetMethodInfo();
Expand All @@ -85,11 +80,24 @@ public void RunMember_SomeBenchmarksBenchmark1_TestResultName()
testListener.Received(1).TestFinished(Arg.Any<TestResult>());
testListener.Received().TestFinished(Arg.Is<TestResult>(r => r.Name == testName));
}

[Test]
public void RunMember_ConfigTypeNotIConfig_ErrorWithWarning()
{
var benchmarkTestRunner = new BenchmarkTestRunner(typeof(object));
var testListener = Substitute.For<ITestListener>();
var targetType = typeof(SomeBenchmarks).GetTypeInfo();

var testRunState = benchmarkTestRunner.RunMember(testListener, targetType.Assembly, targetType);

Assert.That(testRunState, Is.EqualTo(TestRunState.Error));
testListener.Received(1).WriteLine(Arg.Any<string>(), Category.Warning);
}
}

class SuperQuickConfig : ManualConfig
class QuickConfig : ManualConfig
{
internal SuperQuickConfig()
public QuickConfig()
{
Add(Job.Default
.WithLaunchCount(1) // benchmark process will be launched only once
Expand Down