Get exception when stubbing a property - testing

When I run the following test:
[TestMethod]
public void MyTest()
{
var wizardCatalog = MockRepository.GenerateStub<IWizardCatalog>();
var firstQuestion = MockRepository.GenerateStub<IWizardQuestion>();
wizardCatalog.Stub(i => i.GetFirstQuestion()).Return(firstQuestion);
var choices = new List<IWizardChoice>();
firstQuestion.Stub(i => i.Choices).Return(choices);
}
I get this exception:
You are trying to set an expectation on a property that was defined to
use PropertyBehavior. Instead of writing code such as this:
mockObject.Stub(x => x.SomeProperty).Return(42); You can use the
property directly to achieve the same result: mockObject.SomeProperty
= 42;
Everything I read tells me that this stub operation is valid:
var choices = new List<IWizardChoice>();
firstQuestion.Stub(i => i.Choices).Return(choices);
What is going on?

PropertyBehaviour is on by default on stubs, but not on mocks. So you can either continue using a stub and change to the syntax suggested in the exception, or create a mock with GenerateMock<IWizardQuestion>() and use your existing .Stub(...).Return(...) syntax.

Related

Checking exceptions with TestCaseData parameters

I'm using NUnit 3 TestCaseData objects to feed test data to tests and Fluent Assertions library to check exceptions thrown.
Typically my TestCaseData object contains two parameters param1 and param2 used to create an instance of some object within the test and upon which I then invoke methods that should/should not throw exceptions, like this:
var subject = new Subject(param1, param2);
subject.Invoking(s => s.Add()).Should().NotThrow();
or
var subject = new Subject(param1, param2);
subject.Invoking(s => s.Add()).Should().Throw<ApplicationException>();
Is there a way to pass NotThrow() and Throw<ApplicationException>() parts as specific conditions in a third parameter in TestCaseData object to be used in the test? Basically I want to parameterize the test's expected result (it may be an exception of some type or no exception at all).
[TestCaseData] is meant for Test Case Data, not for assertions methods.
I would keep the NotThrow and Throw in separate tests to maintain readability.
If they share a lot of setup-logic, I would extract that into shared methods to reduce the size of the test method bodies.
TestCaseData accepts compile time values, whereas TestCaseSource generates them on runtime, which would be necessary to use Throw and NotThrow.
Here's a way to do it by misusing TestCaseSource.
The result is an unreadable test method, so please don't use this anywhere.
Anyway here goes:
[TestFixture]
public class ActionTests
{
private static IEnumerable<TestCaseData> ActionTestCaseData
{
get
{
yield return new TestCaseData((Action)(() => throw new Exception()), (Action<Action>)(act => act.Should().Throw<Exception>()));
yield return new TestCaseData((Action)(() => {}), (Action<Action>)(act => act.Should().NotThrow()));
}
}
[Test]
[TestCaseSource(typeof(ActionTests), nameof(ActionTestCaseData))]
public void Calculate_Success(Action act, Action<Action> assert)
{
assert(act);
}
}
I ended up using this:
using ExceptionResult = Action<System.Func<UserDetail>>;
[Test]
[TestCaseSource(typeof(UserEndpointTests), nameof(AddUserTestCases))]
public void User_Add(string creatorUsername, Role role, ExceptionResult result)
{
var endpoint = new UserEndpoint(creatorUsername);
var person = GeneratePerson();
var request = GenerateCreateUserRequest(person, role);
// Assertion comes here
result(endpoint.Invoking(e => e.Add(request)));
}
private static IEnumerable AddUserTestCases
{
get
{
yield return new TestCaseData(TestUserEmail, Role.User, new ExceptionResult(x => x.Should().Throw<ApplicationException>())
.SetName("{m} (Regular User => Regular User)")
.SetDescription("User with Regular User role cannot add any users.");
yield return new TestCaseData(TestAdminEmail, Role.Admin, new ExceptionResult(x => x.Should().NotThrow())
)
.SetName("{m} (Admin => Admin)")
.SetDescription("User with Admin role adds another user with Admin role.");
}
}
No big issues with readability, besides, SetName() and SetDescription() methods in the test case source help with that.

Why is ruleSet not recognized in WebForms?

Given this validator:
public ThingValidator()
{
RuleSet("Subgroup", () =>
{
RuleFor(x => x.Apple).NotEmpty();
RuleFor(x => x.Peach).NotEmpty();
});
}
According to the documentation, the 'ruleSet' option should use my named ruleset. However, the suleSet symbol cannot be resolved.
var validator = new ThingValidator();
var thing = new Constituent();
var results = validator.Validate(thing, ruleSet: "Subgroup");
What am I missing?
I was stuck on this as well, but when I looked into the code, I found that while IValidator<T> has a Validate method, there are also Validate extensions methods in DefaultValidatorExtensions. The call with the ruleSet parameter in #mmcglynn's answer is actually to this extension method from DefaultValidatorExtensions:
public static ValidationResult Validate<T>(
this IValidator<T> validator, T instance,
IValidatorSelector selector = null,
string ruleSet = null)
This is why Resharper thinks that the ruleSet variable is unused - because it is not actually passed in. The string "children" passed in is for the 3rd parameter called ruleset, whereas the second parameter (which can take the RulesetValidatorSelector object) defaults to null.
This is extension method, declare namespace using FluentValidation and you can use it.
I think what you need it:
var results = validator.Validate(constituent, new RulesetValidatorSelector("Subgroup"));
or, closer to the example in the FluentValidation documentation
RulesetValidatorSelector ruleSet = new RulesetValidatorSelector();
var results = validator.Validate(constituent, ruleSet: "Children");
This will work, but ReSharper thinks that the ruleSet local variable is unused.

Rhino AutoMocker and Stubs

I am using Joshua Flanagan article “Auto mocking Explained” as a guide. In the article there is a section called “The same tests, with automocker would look like this”. I used this information to build code to run the automocker.
As you can see below answer is a list returned from the BLL. Answer does have one row in it; however, all fields are null. So the test for boo fails. Any tips and hints would be greatly appreciated.
[Test]
public void GetStaffListAndRolesByTeam_CallBLLWithDALStub()
{
// Build List<> data for stub
List<StaffRoleByTeamCV> stubData = new List<StaffRoleByTeamCV>();
StaffRoleByTeamCV stubRow = new StaffRoleByTeamCV();
stubRow.Role = "boo";
stubRow.StaffId = 12;
stubRow.StaffName = "Way Cool";
stubData.Add(stubRow);
// create the automocker
var autoMocker = new RhinoAutoMocker<PeteTestBLL>();
// get instance of test class (the BLL)
var peteTestBllHdl = autoMocker.ClassUnderTest;
// stub out call to DAL inside of BLL
autoMocker.Get<IPeteTestDAL>().Stub(c => c.GetStaffListAndRolesByTeam("4146")).Return(stubData);
// make call to BLL this should return stubData
List<StaffRoleByTeamCV> answer = peteTestBllHdl.GetStaffListAndRolesByTeam("4146");
// do simple asserts to test stubData present
// this passes
Assert.IsTrue(1 == answer.Count, "Did not find any rows");
// this fails
Assert.IsTrue(answer[0].Role == "boo", "boo was not found");
}
I tried using MockMode.AAA but still no joy
An new version of AutoMocker (1.0.3) is available. The new version supports relay mode as in this example..
[TestMethod]
public void ShouldSupportOrderedTest()
{
//Arrange
var autoMocker = new RhinoAutoMocker<CustomerUpdater>();
var mockRepository = autoMocker.Repository;
using (mockRepository.Ordered())
{
autoMocker.Get<ICustomerDataProvider>().Expect(x => x.GetCustomer(Arg<int>.Is.Anything)).Return(new CustomerItem());
autoMocker.Get<ICustomerDataProvider>().Expect(x => x.UpdateCustomer(Arg<CustomerItem>.Is.Anything));
autoMocker.Get<ILogWriter>().Expect(x => x.Write(Arg<string>.Is.Anything));
autoMocker.Get<ILogWriter>().Expect(x => x.Write(Arg<string>.Is.Anything));
autoMocker.Get<IMailSender>().Expect(x => x.SendMail(Arg<string>.Is.Anything, Arg<string>.Is.Anything));
}
//Act
autoMocker.ClassUnderTest.UpdateCustomerName(1, "Frank", "frank#somecompany.com");
//Assert
ExceptionAssert.Throws<ExpectationViolationException>(mockRepository.VerifyAll,"IMailSender.SendMail(anything, anything); Expected #1, Actual #0.\r\nILogWriter.Write(anything); Expected #1, Actual #0.\r\n");
}
I haven't tried, but this article suggests that by default all the mocks created by automocker are not replayed:
http://www.lostechies.com/blogs/joshuaflanagan/archive/2008/09/25/arrange-act-assert-with-structuremap-rhinoautomocker.aspx
Yes that was true for the previous version. But was changed to support ordered tests in version 1.0.3.

Can Rhino stub out a dictionary so that no matter what key is used the same value comes back?

var fakeRoles = MockRepository.GenerateStub < IDictionary<PermissionLevel, string>>();
fakeRoles[PermissionLevel.Developer] = "Developer";
fakeRoles[PermissionLevel.DeveloperManager] = "Developer Manager";
This is specific to what that method happens to be calling, and is irrelevant for the sake of my unit test.
I'd rather do this:
fakeRoles.Stub(r => r[PermissionLevel.None]).IgnoreArguments().Return("Developer");
But I get an exception telling me to set the properties directly. Is there a way to tell rhino to just return the same value for any key given to this stub IDictionary?
What you are trying to do is not a stub (in RhinoMock's understanding), you have to create a mock:
var fakeRoles = MockRepository.GenerateMock < IDictionary<PermissionLevel, string>>();
fakeRoles.Expect(r => r[PermissionLevel.None]).IgnoreArguments().Return("Developer");

Rhino Mocks: Repeat.Once() not working?

Can anyone tell me why in the world the following test is not failing?
[Test]
public void uhh_what() {
var a = MockRepository.GenerateMock<IPrebuiltNotifier>();
a.Expect(x => x.Notify()).Repeat.Once();
a.Notify();
a.Notify();
a.VerifyAllExpectations();
}
Really need a second pair of eyes to confirm I'm not crazy...now I'm worried that all my tests are unreliable.
There is already a thread on the RhinoMocks group.
GenerateMock creates a dynamic mock. The dynamic mock allows calls that are not specified (=expected). If this happens, it just returns null (or the default value of the return type).
Note: Repeat is a specification of the behaviour (like Stub), not the expectation even if specified in an expectation.
If you want to avoid having more then a certain number of calls, you could write:
[Test]
public void uhh_what()
{
var a = MockRepository.GenerateMock<IPrebuiltNotifier>();
a.Expect(x => x.Notify()).Repeat.Once();
a.Stub(x => x.Notify()).Throw(new InvalidOperationException("gotcha"));
a.Notify();
// this fails
a.Notify();
a.VerifyAllExpectations();
}
Or
[Test]
public void uhh_what()
{
var a = MockRepository.GenerateMock<IPrebuiltNotifier>();
a.Notify();
a.Notify();
// this fails
a.AssertWasCalled(
x => x.Notify(),
o => o.Repeat.Once());
}
When using GenerateMock (or with Dynamic Mocks in general) I always mentally insert the following:
a.Expect(x => x.Notify()).Repeat.*[AtLeast]*Once();