I'm setting up some RhinoMock tests but I can't work out why my expectations are failing.
Here are the class/ interface I'm testing:
public class LogOn {
public virtual ILogOn View { get; set; }
public virtual IDataProvider DataProvider { get; set; }
public void SetUp(ILogOn view) {
this.View = view;
this.DataProvider = ... //using dependancy injection to do the data provider, so I want it faked in tests
}
public void SetUpEvents() {
this.View.Submit += new EventHandler(View_Submit);
}
void View_Submit(object sender, EventArgs e) {
if ( this.DataProvider.LogOn(this.Username) ) {
this.View.SubmitSuccess();
} else {
this.View.SubmitFailure("Username is incorrect");
}
}
}
public interface ILogOn {
string Username { get; set; }
event EventHandler Submit;
void SubmitSuccess();
void SubmitFailure(string message);
}
And here is my test method:
[TestMethod]
public void LogOnFailure() {
var dataProvider = MockRepository.CreateStub<DataProvider>();
var presenter = MockRepository.CreateMock<LogOn>();
var view = MockRepository.CreateMock<ILogOn>();
dataProvider.Expect(d => d.LogOn(null)).Return(true).Repeat.Any();
presenter.Expect(p => p.DataProvider).Return(dataProvider).Repeat.Any();
presenter.Expect(p => p.View).Return(view).Repeat.Any();
presenter.Expect(p => p.SetUpEvents()).CallOriginalMethod();
view.Expect(v => v.Username).Return("invalid").Repeat.Any();
view.Expect(v => v.SubmitFail(null)).Constraints(Is.Same("Username is incorrect"));
presenter.SetUp(view);
presenter.SetUpEvents();
view.Raise(v => v.Submit += null, null, EventArgs.Empty);
presenter.VerifyAllExpectations();
view.VerifyAllExpectations();
}
The expectation that is failing is:
view.Expect(v => v.SubmitFail(null)).Constraints(Is.Same("Username is incorrect"));
(indicated by view.VerifyAllExpectations)
It says that that method is never executed, but when using the debugger I can step through and LogOn.View is accessed, does call the SubmitFailure method (with that argument) and return correctly.
I can't work out what is missing as watching the code does indicate that everything is executed at the right time and with the right values.
Edit: Ok, so I let out the code which is why I was mocking the LogOn class, it has a dependancy of an external data provider (which I'm stubbing as I don't care how it works). My appologies, I thought I was making this clearer but just made is worse!
The LogOn class is your system under test, so you should not be mocking that. You want to test that the LogOn class behaves as it should in the case of an invalid username. You are able to determine the correct behavior by passing in a mocked view that sets up the scenario you want. Try changing your test to what I have below.
[TestMethod]
public void LogonFailure()
{
var presenter = new LogOn();
var view = MockRepository.CreateMock<ILogOn>();
view.Expect(v => v.Username).Return("invalid").Repeat.Any();
view.Expect(v => v.SubmitFail(null)).Constraints(Is.Same("Username is incorrect"));
presenter.Setup(view);
view.Raise(v => v.Submit += null, null, EventArgs.Empty);
view.VerifyAllExpectations();
}
Related
I have a piece of code from an old book on MVVM which works, but a test using Rhino Mocks fails with this message:
Test method TestProject.UnitTest1.UpdateCustomer_Always_CallsUpdateWithCustomer threw exception:
Rhino.Mocks.Exceptions.ExpectationViolationException: DataProvider.DoSomething(ConsoleApp.Customer); Expected #1, Actual #0
I'm providing an example which I think is equivalent:
namespace ConsoleApp {
class Program { static void Main () { } }
public class Customer { public string ID { get; set; } }
public class DataProvider {
public virtual Customer GetCustomer (string id) => new Customer ();
public virtual void DoSomething (Customer customer) { }
}
public class ViewModel {
DataProvider _dataProvider;
Customer _customer;
public ViewModel (DataProvider dataProvider, string id) {
_dataProvider = dataProvider;
_customer = new Customer { ID = id };
}
public void DoSomething () => _dataProvider.DoSomething (_customer);
}
}
and the test that fails
namespace TestProject {
[TestClass]
public class UnitTest1 {
[TestMethod]
public void UpdateCustomer_Always_CallsUpdateWithCustomer () {
DataProvider dataProviderMock = MockRepository.GenerateMock<DataProvider> ();
Customer expectedCustomer = new Customer ();
dataProviderMock.Stub (u => u.GetCustomer (Arg<string>.Is.Anything)).Return (expectedCustomer);
ViewModel target = new ViewModel (dataProviderMock, string.Empty);
target.DoSomething ();
dataProviderMock.AssertWasCalled (d => d.DoSomething (expectedCustomer));
}
}
}
I read several posts on this result, e.g. 1 and 2, but this doesn't help me. I read this answer which seems interesting:
I usually get this error when a stubbed method is called with an object argument
that I build in the test and in the tested code the object is built before calling that method.
While this could be a reason for the Rhino Mocks to fail, it seems to be a bug.
My question is: Is there something wrong in my test and there is a bug in Rhino Mocks, or is there a problem with my code?
The test stubs DataProvider.GetCustomer to return an expected customer instance to be used in the assertion, but the example view model does not invoke DataProvider.GetCustomer.
It is using the one initialized in the constructor.
//...
public ViewModel (DataProvider dataProvider, string id) {
_dataProvider = dataProvider;
_customer = new Customer { ID = id };
}
//...
Thus the exception thrown by the test is accurate given the shown example.
That is because the actual instance used by the view model will not be the one used in the assertion when the test is exercised.
//...
dataProviderMock.AssertWasCalled (d => d.DoSomething (expectedCustomer));
In order for the test to behave as expected based on its arrangement the view model would actually have be refactored to decouple from initializing the Customer
For example
public class ViewModel {
DataProvider _dataProvider;
string id;
public ViewModel (DataProvider dataProvider, string id) {
_dataProvider = dataProvider;
this.id = id;
}
public void DoSomething () {
Customer customer = _dataProvider.GetCustomer(id);
_dataProvider.DoSomething (_customer);
}
}
The test should also be more explicit about what it is trying to test
[TestClass]
public class UnitTest1 {
[TestMethod]
public void UpdateCustomer_Always_CallsUpdateWithCustomer () {
//Arrange
DataProvider dataProviderMock = MockRepository.GenerateMock<DataProvider> ();
string id = "FakeId";
Customer expectedCustomer = new Customer { ID = id };
dataProviderMock.Stub (u => u.GetCustomer (id))
.Return (expectedCustomer);
ViewModel target = new ViewModel (dataProviderMock, id);
//Act
target.DoSomething ();
//Assert
dataProviderMock.AssertWasCalled (d => d.DoSomething (expectedCustomer));
}
}
Alternatively, if the view model is as intended then the test needs to assert its expectations differently
[TestClass]
public class UnitTest1 {
[TestMethod]
public void UpdateCustomer_Always_CallsUpdateWithCustomer () {
//Arrange
DataProvider dataProviderMock = MockRepository.GenerateMock<DataProvider> ();
string id = "FakeId";
ViewModel target = new ViewModel (dataProviderMock, id);
//Act
target.DoSomething ();
//Assert
dataProviderMock
.AssertWasCalled (d => d.DoSomething (Arg<Customer>.Matches(c => c.ID == id));
}
}
Note the delegate used in the assertion to verify the characteristics of the expected argument instead of the specific instance passed when it was invoked.
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.
I am creating an application in ASP.NET web form with MVP pattern. I am getting some issues working with TDD. I have created two test, one is working fine but when a second test is executed it throws an error.
Below is my declared View
public interface IAddUpdateView : IView
{
string Type { get; set; }
string PageTitle { set; }
string Details { get; set; }
bool Active { get; set; }
}
Presenter
// BasePresenter is an abstract class contains abstract method with name Initialize()
public class MyPresenter: BasePresenter<IAddUpdateView >
{
private readonly IDatabaseLayer _databaselayer;
public MyPresenter(IAddUpdateView view, IDatabaseLayer databaseLayer) : base(view)
{
_databaselayer = databaseLayer;
}
public override void Initialize()
{ }
public void Initialize(string str)
{
string[] str1=Misc.DecryptURL(str);
View.Type = str1[0].ToString(); // ERROR LINE
if (View.Type.ToLower().Trim() == "add")
{
View.PageTitle = "Add New Task";
}
else if (View.Type.ToLower().Trim() == "edit")
{
}
}
}
Now I am working on creating unit test mocking the Presenter class to test the dependencies using Rhino mocks.
That's my test class with just two test methods. These test methods test when loading a View it calls appropriate Page Type.
When ADD type is called, it get the View.Type as "add" and when Edit type is called, it verifies for the specific object that is loaded.
[TestFixture]
public class MyPresenterTest
{
private IAddUpdateView _view;
private MyPresernter _controller;
[SetUp]
public void SetUp()
{
_view = MockRepository.GenerateMock<IAddUpdateView >();
_controller = new MyPresernter (_view, MockDataLayer());
}
[TearDown]
public void TearDown() { _controller = null; _view = null; }
// TEST 1
[Test]
public void When_Loading_for_Add_View_Panel_Return_Type_Add()
{
// Arrange
_view.Stub(x => x.Type).PropertyBehavior();
//Act
_controller.Initialize(GetURLWithAddValue());
// GetURLWithAddValue: This method get the URL with querystring contains value as "add"
//Assert
Assert.AreEqual("add",_view.Type);
}
TEST 2
// When this test method is run, It has the Type="edit", but in my
presenter View.Type (see LINE ERROR), my Type is null even I
assigned the values.
[Test]
public void When_Loading_for_Edit_View_Panel_Load_Correct_Object()
{
// Arrange
_view.Stub(x =>x.TaskDetails).PropertyBehavior();
//Act
Task o=new Task(){ TaskId=6, TASK_NAME="Task 6"};
_controller.Initialize(GetURLWithEditValue(o));
//Assert
Assert.AreEqual(o.TASK_NAME, _view.TaskDetails);
}
private static IDatabaseLayer MockDataLayer()
{
IDatabaseLayer obj = MockRepository.GenerateMock<IDatabaseLayer>();
MockTaskDataLayer a = new MockTaskDataLayer();
obj.Stub(x => x.GetList());
return obj;
}
}
Can someone guide me why Test 1 get passed and when Test 2 is executed, after assigning a value in View.Type (see LINE ERROR in MyPresenter class) it's still null??
Thanks,
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
I've have searched on this and it seems to be a catch all, unfortunately everything I've read doesn't help figure it out. Here is the class:
public interface IMockInterface
{
MockClass MockedMethod();
MockClass MockThis();
}
public class MockClass : IMockInterface
{
public virtual MockClass MockedMethod()
{
MockClass returnValue;
returnValue = new MockClass();
returnValue.SomeMessage = "Not mocked";
return returnValue;
}
public MockClass MockThis()
{
MockClass mock;
MockClass returnValue;
mock = new MockClass();
return mock.MockedMethod();
}
}
And the test:
public void MockTest_Internal()
{
MockClass mainClass;
MockClass returnedClass;
IMockInterface mockProvider;
mainClass = new MockClass();
mockProvider = repository.StrictMock<IMockInterface>();
Expect.Call(mockProvider.MockedMethod())
.Return(new MockClass { SomeMessage = "Mocked" });
repository.ReplayAll();
returnedClass = mainClass.MockThis();
provider.AssertWasCalled(item => item.MockedMethod());
Assert.IsTrue(returnedClass.SomeMessage == "Mocked");
}
And have also tried and doesn't work
But I keep getting this exception:
Rhino.Mocks.Exceptions.ExpectationViolationException:
IMockInterface.MockedMethod(); Expected #1, Actual #0
Now from what I've read this would suggest either the method was called with different than expected parameters OR the method was never called but was expected to be called. This isn't the case for the test.
Side Note: This is my first time really using Rhino.Mocks without some in house code so I am basically picking it up as I go. There could be something really stupid here...
This was the old test commented on, but is not what I should have been using:
public void MockTest_Internal()
{
MockClass mainClass;
MockClass returnedClass;
IMockInterface mockProvider;
mainClass = new MockClass();
var provider = MockRepository.GenerateStub<IMockInterface>();
provider.Stub(item => item.MockedMethod())
.Return(new MockClass { SomeMessage = "Mocked" });
returnedClass = mainClass.MockThis();
provider.AssertWasCalled(item => item.MockedMethod());
Assert.IsTrue(returnedClass.SomeMessage == "Mocked");
}
You're telling the mock framework to stub the MockedMethod class on the provider object, but you never inject the provider into the mainClass object to be used. It's not clear to me what you are trying to accomplish but if you want the mocked method to be called then it has to be called on the object on which the stub was set up.
If you define MockThis as below, I think you will find that it will work.
public MockClass MockThis(IMockInterface provider)
{
return provider.MockMethod();
}
The bottom line is that you get the exception because the method was never called on the provider, only on the mainClass object.
EDIT: Example
public class ClassUnderTest
{
private ProviderClass provider { get; set; }
public ClassUnderTest( ProviderClass provider )
{
this.Provider = provider;
}
public int DoOperation()
{
return this.Provider.ProviderOperation();
}
}
public class ProviderClass
{
private int value = 42;
public ProviderClass()
{
}
public virtual int ProviderOperation()
{
return this.value;
}
}
[TestMethod]
public void DoOperationTest()
{
ProviderClass mockProvider = MockRepository.GenerateMock<ProviderClass>();
mockProvider.Expect( mp => mp.ProviderOperation() ).Return( -1 );
ClassUnderTest target = new ClassUnderTest( mockProvider );
int expectedValue = -1;
int value = target.DoOperation();
Assert.AreEqual( expectedValue, value );
mockProvider.VerifyAllExpectations();
}
Normally the ProviderClass object would return 42 from the ProviderOperation method, but we've mocked it out and told it to return -1. When the ClassUnderTest DoOperation method is called, the mock provider object's ProviderOperation method is invoked and returns the mocked value of -1.
Hope this helps.
I usually get this error when a stubbed method is called with an object argument that I build in the test and in the tested code the object is built before calling that method. The solution is to use the Rhino.Mocks Matches().
Ex:
Arg<string>.Matches(s => s.Contains("some substring"))