Nunit: Custom Test Execution - c#

I have a custom TestMethodAttribute in MSTest and want to build something similar in NUnit.
The Custom TestMethodAttribute in MSTest:
public class CustomTestMethod : TestMethodAttribute
{
public override TestResult[] Execute(ITestMethod testMethod)
{
if(SomeConditon){
var results = new[]
{
new TestResult
{
Outcome = UnitTestOutcome.Inconclusive,
TestContextMessages = "Test Skipped"
}
};
return results;
}
return base.Execute(testMethod);
}
}
I this possible in Nunit and yes how can I do this?

Related

Partial mock methods in a class using Autofixture, Moq and XUnit

I want to mock only some methods of a class and call the real implementation for other methods.
I have my sut class Test where the Runner class is injected in the constructor. This injected class has again a injected other class RunnerParam in the constructor.
The code is a simplified case of my real classes in trying to have only the basics.
[Fact]
public void Test()
{
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var paramMock = fixture.Freeze<Mock<IRunnerParam>>();
paramMock.Setup(x => x.Multiplicator()).Returns(2);
var classMock = fixture.Freeze<Mock<IRunner>>();
classMock.Setup(x => x.Run()).Returns(5);
var test = fixture.Create<Test>();
var result = test.StartRunning(); // should be 5
var result2 = test.StartRunningImplementation(5); // should be 500
}
Supporting members
public interface IRunnerParam
{
int Multiplicator();
}
public class RunnerParam : IRunnerParam
{
public virtual int Multiplicator()
{
return 20;
}
}
public interface IRunner
{
int Run();
int RunImplementation(int param);
}
public class Runner : IRunner
{
protected virtual RunnerParam MultiParam { get; set; }
public Runner(RunnerParam multiParam)
{
MultiParam = multiParam;
}
public virtual int Run()
{
return 10;
}
public int RunImplementation(int param)
{
return 10 * MultiParam.Multiplicator() * param * Run();
}
}
public class Test
{
private readonly IRunner _runner;
public Test(IRunner runner)
{
_runner = runner;
}
public int StartRunning()
{
return _runner.Run();
}
public int StartRunningImplementation(int param)
{
return _runner.RunImplementation(param);
}
}
I want to mock and give a mocked value to the method Run in the class Runner, but to use the real implementation of the method RunImplementation.
I would expect to see for result2 500, but it's 0, meaning that the method is not seen as mocked up. In my eyes that is correct, but the Moq callbase is equal to true, so the real implementation should be taken, but it isn't.
What am I missing here?
In the shown simplified example, Test is only dependent on IRunner
private readonly IRunner _runner;
public Test(IRunner runner)
{
_runner = runner;
}
So that is all that needs to be mocked if the intention was to test Test class in isolation.
//...
var classMock = fixture.Freeze<Mock<IRunner>>();
classMock.Setup(x => x.Run()).Returns(5);
classMock.Setup(x => x.RunImplementation(It.IsAny<int>())).Returns(500);
//...
If Runner class is to be also tested in isolation, then a mocked RunnerParam would be needed to satisfy its dependencies.
It should however be dependent on the abstraction (interface) and not the concretion (implementation).
protected virtual IRunnerParam MultiParam { get; set; }
public Runner(IRunnerParam multiParam) {
MultiParam = multiParam;
}
This simplifies the isolated test as described in the original question
I want to mock and give a mocked value to the method Run in the class Runner, but to use the real implementation of the method RunImplementation.
//Arrange
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var runnerParam = fixture.Freeze<Mock<IRunnerParam>>()
.Setup(_ => _.Multiplicator())
.Returns(2);
var subjectMock = fixture.Freeze<Mock<Runner>>();
subjectMock.CallBase = true;
subjectMock.Setup(_ => _.Run()).Returns(5);
int expected = 500;
Runner sut = subjectMock.Object;
//Act
var actual = sut.RunImplementation(5); // should be 500
//Assert
actual.Should().Be(expected);

How to order xUnit tests belonging to one test collection but spread across multiple test classes?

I have some test methods which are spread across multiple test classes but belonging to single test collection. I am using ITestCaseOrderer provided by xUnit but it is ordering only test methods within individual test classes.
[AttributeUsage(AttributeTargets.Method)]
public class TestPriorityAttribute : Attribute
{
public TestPriorityAttribute(int priority)
{
this.Priority = priority;
}
public int Priority { get; }
}
I have implemented my priority orderer in the below fashion.
public class PriorityOrderer : ITestCaseOrderer
{
public IEnumerable<TTestCase> OrderTestCases<TTestCase>(IEnumerable<TTestCase> testCases) where TTestCase : ITestCase
{
var sortedMethods = new Dictionary<int, TTestCase>();
foreach (var testCase in testCases)
{
var attributeInfo = testCase.TestMethod.Method.GetCustomAttributes(typeof(TestPriorityAttribute).AssemblyQualifiedName)
.SingleOrDefault();
if (attributeInfo != null)
{
var priority = attributeInfo.GetNamedArgument<int>("Priority");
sortedMethods.Add(priority, testCase);
}
}
return sortedMethods.OrderBy(x => x.Key).Select(x => x.Value);
}
}
My First test class looks like this.
[TestCaseOrderer("Integration.Tests.PriorityOrderer", "CompanyName.ProjectName.Integration.Tests")]
[Collection("StandardIntegrationTests")]
[Trait("Category", "Integration")]
public class StandardControllerTests1
{
public StandardControllerTests1(StandardIntegrationTestFixture standardIntegrationTestFixture)
{
}
[Fact, TestPriority(1)]
public void TestMethod1()
{
}
[Fact, TestPriority(2)]
public void TestMethod2()
{
}
}
My Second test class looks like this
[TestCaseOrderer("Integration.Tests.PriorityOrderer", "CompanyName.ProjectName.Integration.Tests")]
[Collection("StandardIntegrationTests")]
[Trait("Category", "Integration")]
public class StandardControllerTests2
{
public StandardControllerTests2(StandardIntegrationTestFixture standardIntegrationTestFixture)
{
}
[Fact, TestPriority(3)]
public void TestMethod3()
{
}
[Fact, TestPriority(4)]
public void TestMethod4()
{
}
}
I have other test classes also which belong to same test collection. When I run the tests, It is not ordering across the collection. How do I order these tests to run in order which are in same collection?
I have run into this same issue while building a ordering system to run tests in parallel with xUnit while also running some with dependencies within their own collections.
According to a Issue 898 on the xUnit board ordering across classes in the same collection is not possible at this time.
The work around I used was to organize the tests which needed sequenced into the same class with different files using partial class so that the tests could still be kept organized into different files.
[Trait("Order", "")]
[TestCaseOrderer(DependencyOrderer.TypeName, DependencyOrderer.AssemblyName)]
public partial class OrderTests
{
[Fact]
public void Test0()
{
Thread.Sleep(TimeSpan.FromSeconds(1));
}
[Fact]
[TestDependency("Test1", "Test0")]
public void Test3()
{
Thread.Sleep(TimeSpan.FromSeconds(1));
}
}
[Trait("Order", "")]
public partial class OrderTests
{
[Fact]
public void Test2()
{
Thread.Sleep(TimeSpan.FromSeconds(1));
}
[Fact]
[TestDependency("Test0")]
public void Test1()
{
Thread.Sleep(TimeSpan.FromSeconds(1));
}
}

Override Autofixture customization setup

I've a class with several services injected in its constructor. I'm using Autofixture with xUnit.net and NSubstitute, and created an attribute to setup the global customization.
public class AutoDbDataAttribute : AutoDataAttribute
{
public AutoDbDataAttribute() : base(() => new Fixture().Customize(new AutoNSubstituteCustomization()))
{
}
public AutoDbDataAttribute(Type customizationType) : base(() =>
{
var customization = Activator.CreateInstance(customizationType) as ICustomization;
var fixture = new Fixture();
fixture.Customize(new AutoNSubstituteCustomization());
fixture.Customize(customization);
return fixture;
})
{
}
}
I also have a custom customization class that setups the common customization for the test methods in the same class.
public class RevenueProviderCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Register<IRevenueContextService>(() =>
{
var contextService = Substitute.For<IRevenueContextService>();
contextService.GetContext().Returns(fixture.Create<RevenueContext>());
return contextService;
});
fixture.Register<ICompanyService>(() =>
{
var companyService = Substitute.For<ICompanyService>();
companyService.Get(Arg.Any<Guid>()).Returns(fixture.Create<Company>());
return companyService;
});
}
}
Now, some of my tests depend on modifying specific properties in the objects returned by the services. So in some cases, I want to modify the RevenueContext and in some cases, I want to modify the Company data.
What I did was creating another object inside the test itself and modify the Returns of the service with the new object, like this:
[Theory]
[AutoDbData(typeof(RevenueProviderCustomization))]
public void ShouldReturnCompanyRevenue(RevenueProvider sut, Company company, [Frozen]IRevenueContextService contextService)
{
var fixture = new Fixture();
RevenueContext context = fixture.Build<RevenueContext>().With(c => c.DepartmentId, null).Create();
contextService.GetContext().Returns(context);
sut.GetRevenue().Should().Be(company.Revenue);
}
But this doesn't work. The RevenueContext from the RevenueProviderCustomization is still used.
Does anyone know how I can override the return from the service? I don't want to setup the fixture one by one in my test, so I was hoping to be able to create a 'general setup' and modify as needed according to the test case.
UPDATE 1
Trying the answer from Mark, I changed the test to
[Theory]
[AutoDbData(typeof(RevenueProviderCustomization))]
public void ShouldReturnCompanyRevenue([Frozen]IRevenueContextService contextService, [Frozen]Company company, RevenueProvider sut, RevenueContext context)
{
context.DepartmentId = null;
contextService.GetContext().Returns(context);
sut.GetRevenue().Should().Be(company.Revenue);
}
The problem is because the RevenueContext is called in the RevenueProvider constructor. So my modification to the DepartmentId happens after the call was made.
public RevenueProvider(IRevenueContextService contextService, ICompanyService companyService)
{
_contextService = contextService;
_companyService = companyService;
_company = GetCompany();
}
public double GetRevenue()
{
if (_hasDepartmentContext)
return _company.Departments.Single(d => d.Id == _departmentId).Revenue;
else
return _company.Revenue;
}
private Company GetCompany()
{
RevenueContext context = _contextService.GetContext();
if (context.DepartmentId.HasValue)
{
_hasDepartmentContext = true;
_departmentId = context.DepartmentId.Value;
}
return _companyService.Get(context.CompanyId);
}
Assuming that RevenueProvider essentially looks like this:
public class RevenueProvider
{
private readonly ICompanyService companySvc;
public RevenueProvider(ICompanyService companySvc)
{
this.companySvc = companySvc;
}
public object GetRevenue()
{
var company = this.companySvc.Get(Guid.Empty);
return company.Revenue;
}
}
Then the following test passes:
[Theory]
[AutoDbData(typeof(RevenueProviderCustomization))]
public void ShouldReturnCompanyRevenue(
[Frozen]ICompanyService companySvc,
RevenueProvider sut,
Company company)
{
companySvc.Get(Arg.Any<Guid>()).Returns(company);
var actual = sut.GetRevenue();
Assert.Equal(company.Revenue, actual);
}
This scenario is exactly what the [Frozen] attribute is designed to handle. The various attributes that AutoFixture defines are applied in the order of the arguments. This is by design, because it enables you to pull out a few values from the argument list before you freeze a type.
In the OP, [Frozen] is only applied after sut, which is the reason the configuration of the mock doesn't apply within the SUT.

TestScheduler not working like expected on subscribed property (w throttle)

I'm pretty green with rx/ReactiveUi and want to write a xunit test using TestScheduler to check if the throttle for retrieving search suggestions is working properly.
The idea is to use the TestScheudler for the timing, change the value for the search-term property and check if an async method is called. Unfortunately the method is not called at the expected position (see attached code, especially the unit test).
What am I missing? Is the way I'm trying to test this a good way to go?
My view Model:
public class MyViewModel : ReactiveObject
{
public MyViewModel (IMyQueryHandler queryHandler)
{
...
// Type suggestions
this.SearchTerms = this.ObservableForProperty(x => x.SearchTerm)
.Throttle(SuggestionThrottle).Value();
this.SearchTerms.Subscribe(this.LoadSearchSuggestionsAsync);
...
}
internal async void LoadSearchSuggestionsAsync(string search)
{
...
this.SearchSuggestions = this.queryHandler.ExecuteQuery(...);
...
}
public IList<SearchSuggestion> SearchSuggestions
{
get { return this.searchSuggestions; }
set { this.RaiseAndSetIfChanged(ref this.searchSuggestions, value); }
}
...
}
My Unit Test (xunit):
...
public class TestFixture : ReactiveObject
{
public string SearchTerms { get { return this._searchTermsBackingField.Value; } }
public ObservableAsPropertyHelper<string> _searchTermsBackingField;
}
[Fact]
public void WillTryToLoadSearchSuggestionsAfterThrottleTime()
{
new TestScheduler().With(
sched =>
{
var fixture = new TestFixture();
var queryClient = Substitute.For<IMyQueryHandler>();
var caseSuggestions = new List<...> { ... }
queryClient.ExecuteQuery<...>(...).ReturnsForAnyArgs(...); // Nsubstitute
var vm = new MyViewModel(queryClient);
vm.SearchTerms.ToProperty(fixture, p => p.SearchTerms, out fixture._searchTermsBackingField);
sched.Schedule(() => vm.SearchTerm = "Tes");
sched.Schedule(MyViewModel.SuggestionThrottle, () => vm.SearchTerm = "Test");
sched.AdvanceBy(MyViewModel.SuggestionThrottle.Ticks);
sched.AdvanceBy(1);
// why is the method MyViewModel.LoadSearchSuggestionsAsync not called here (in debug)???
sched.AdvanceBy(1);
} // method gets called here...
}
...
Throttle doesn't set the scheduler, write Throttle(timespan, RxApp.MainThreadScheduler) instead

Testing FluentValidation PropertyValidator

Is it possible to test a FluentValidation PropertyValidator in isolation?
I know I can test the Validator that's using the PropertyValidator for specific errors but I’d rather test true/false just on the property validator if possible.
Can this be done? If so, how?
I also wanted to test my true / false logic. It is a shame the IsValid method is protected. My work around was to create another IsValid method and have the protected IsValid call through to it.
public class MyValidator: PropertyValidator
{
public MyValidator(
string errorMessage = "default Message") : base(errorMessage)
{
}
protected override bool IsValid(PropertyValidatorContext context)
{
var stringToValidate = context.PropertyValue as String;
return IsValid(stringToValidate);
}
public bool IsValid(string stringToValidate)
{
if (stringToValidate == null)
{
return false;
}
//testing logic here
return true;
}
}
I know this has been a while, but I achieved this as follows:
Custom Validator:
public class MyValidator : PropertyValidator
{
public MyValidator ()
: base("Value must be null or between 0 and 3.")
{
}
protected override bool IsValid(PropertyValidatorContext context)
{
if (context.PropertyValue == null)
{
return true;
}
var value = (decimal)context.PropertyValue;
return value >= 0m && value <= 3m;
}
}
Test Validator:
public class TestValidator : InlineValidator<TestObject>
{
public TestValidator (params Action<TestValidator >[] actions)
{
foreach (var action in actions)
{
action(this);
}
}
}
Test Object:
public class TestObject
{
public TestObject(decimal? val)
{
this.GenericDecimal = val;
}
public decimal? GenericDecimal { get; set; }
}
Test:
[Test]
public void TestIt()
{
var validator = new TestValidator(v => v.RuleFor(obj => obj.GenericDecimal).SetValidator( new MyValidator() ));
Assert.IsTrue(validator.Validate(new TestObject(null)).IsValid);
Assert.IsTrue(validator.Validate(new TestObject(0m)).IsValid);
Assert.IsTrue(validator.Validate(new TestObject(3m)).IsValid);
Assert.IsFalse(validator.Validate(new TestObject(-1m)).IsValid);
Assert.IsFalse(validator.Validate(new TestObject(3.01m)).IsValid);
}
As for version 6.2 of FluentValidation it is possible to build the PropertyValidator.Validate() parameter due to making ValidatorSelectors globally configurable: https://github.com/JeremySkinner/FluentValidation/commit/95376c0519da1a06388be91a97fb5062fd4a162e
In the below example you see how I validate the 'puic' property of Track
Unit test:
public void ExistsInCollectionValidatorTest()
{
var track = new Track()
{
puic = "p1"
};
var sut = new ExistsInCollectionValidator<Track>();
// Build PropertyValidator.Validate() parameter
var selector = ValidatorOptions.ValidatorSelectors.DefaultValidatorSelectorFactory();
var context = new ValidationContext(track, new PropertyChain(), selector);
var propertyValidatorContext = new PropertyValidatorContext(context, PropertyRule.Create<Track,string>(t => t.puic), "puic");
var results = sut.Validate(propertyValidatorContext);
// Assertion..
}

Categories