Tell me if my concept is wrong. I have 2 classes; Country and State. A state will have a CountryId property.
I have a service and a repository as follows:
Service.cs
public LazyList<State> GetStatesInCountry(int countryId)
{
return new LazyList<State>(geographicsRepository.GetStates().Where(s => s.CountryId == countryId));
}
IRepository.cs
public interface IGeographicRepository
{
IQueryable<Country> GetCountries();
Country SaveCountry(Country country);
IQueryable<State> GetStates();
State SaveState(State state);
}
MyTest.cs
private IQueryable<State> getStates()
{
List<State> states = new List<State>();
states.Add(new State(1, 1, "Manchester"));//params are: StateId, CountryId and StateName
states.Add(new State(2, 1, "St. Elizabeth"));
states.Add(new State(2, 2, "St. Lucy"));
return states.AsQueryable();
}
[Test]
public void Can_Get_List_Of_States_In_Country()
{
const int countryId = 1;
//Setup
geographicsRepository.Setup(x => x.GetStates()).Returns(getStates());
//Call
var states = geoService.GetStatesInCountry(countryId);
//Assert
Assert.IsInstanceOf<LazyList<State>>(states);
//How do I write an Assert here to check that the states returned has CountryId = countryId?
geographicsRepository.VerifyAll();
}
I need to verify the information of the states returned. Do I need to write a loop and put the asserts in it?
Assert.IsTrue(states.All(x => 1 == x.CountryId));
I don't know if there is something in nunit for this, but you could do this with linq:
states.All(c => Assert.AreEqual(1, c.CountryId))
EDIT
after quick googling it seems you can do this
Assert.That(states.Select(c => c.CountryId), Is.All.EqualTo(1));
Related
I have this simple Saga in Rebus:
public void MySaga : Saga<MySagaData>
IAmInitiatedBy<Event1>
IHandleMessages<Event2>
{
private IBus bus;
private ILog logger;
public MySaga(IBus bus, ILog logger)
{
if (bus == null) throw new ArgumentNullException("bus");
if (logger == null) throw new ArgumentNullException("logger");
this.bus = bus;
this.logger = logger;
}
protected override void CorrelateMessages(ICorrelationConfig<MySagaData> config)
{
config.Correlate<Event>(m => m.MyObjectId.Id, s => s.Id);
config.Correlate<Event>(m => m.MyObjectId.Id, s => s.Id);
}
public Task Handle(Event1 message)
{
return Task.Run(() =>
{
this.Data.Id = message.MyObjectId.Id;
this.Data.State = MyEnumSagaData.Step1;
var cmd = new ResponseCommandToEvent1(message.MyObjectId);
bus.Send(cmd);
});
}
public Task Handle(Event2 message)
{
return Task.Run(() =>
{
this.Data.State = MyEnumSagaData.Step2;
var cmd = new ResponseCommandToEvent2(message.MyObjectId);
bus.Send(cmd);
});
}
}
and thanks to the kind mookid8000 I can test the saga using FakeBus and a SagaFixture:
[TestInitialize]
public void TestInitialize()
{
var log = new Mock<ILog>();
bus = new FakeBus();
fixture = SagaFixture.For<MySaga>(() => new MySaga(bus, log.Object));
idTest = new MyObjectId(Guid.Parse("1B2E7286-97E5-4978-B5B0-D288D71AD670"));
}
[TestMethod]
public void TestIAmInitiatedBy()
{
evt = new Event1(idTest);
fixture.Deliver(evt);
var testableFixture = fixture.Data.OfType<MySagaData>().First();
Assert.AreEqual(MyEnumSagaData.Step1, testableFixture.State);
// ... more asserts
}
[TestMethod]
public void TestIHandleMessages()
{
evt = new Event2(idTest);
fixture.Deliver(evt);
var testableFixture = fixture.Data.OfType<MySagaData>().First();
Assert.AreEqual(MyEnumSagaData.Step2, testableFixture.State);
// ... more asserts
}
[TestCleanup]
public void TestCleanup()
{
fixture.Dispose();
bus.Dispose();
}
The first test method that check IAmInitiatedBy is correctly executed and no error is thrown, while the second test fail. It looks like a correlation issues since fixture.Data contains no elements and in fixture.LogEvents contains as last elements this error: Could not find existing saga data for message Event2/b91d161b-eb1b-419d-9576-2c13cd9d9c51.
What is this GUID? Is completly different from the one I defined in the unit test? Any ideas? Is legal what I'm tryng to test (since I'm using an in-memory bus)?
This line is bad: this.Data.Id = message.MyObjectId.Id. If you checked the value of Data.Id before you overwrote it, you would have noticed that the property already had a value.
You do not assign the saga ID - Rebus does that. And you should leave that property alone :)
Regarding your error - when Rebus wants to log information about a specific message, it logs a short name for the type and the message ID, i.e. the value of the automatically-assigned rbs2-msg-id header. In other words: It's not the value of the property m.MyObjectId.Id, you're seeing, it's the message ID.
Since the saga fixture is re-initialized for every test run, and you only deliver an Event2 to it (which is not allowed to initiate a new instance), the saga will not be hit.
I am experiencing some weird behavior using MOQ in my unit tests:
Given the following test:
[Fact]
public void ShoppingCart_ShouldIncrementQuantity_WhenAddingDuplicateItem()
{
var cart = new ShoppingCart();
var item1 = GetMockItem("Test");
var item2 = GetMockItem("Test", quantity: 2);
cart.AddItem(item1.Object);
cart.AddItem(item2.Object);
cart.Items.Single(x => x.Sku == "Test").Quantity
.Should().Be(3);
}
private Mock<IShoppingCartItem> GetMockItem(string sku, decimal price = 10, int quantity = 1)
{
var mock = new Mock<IShoppingCartItem>();
mock.Setup(x => x.Sku).Returns(sku);
mock.Setup(x => x.Price).Returns(price);
mock.Setup(x => x.Quantity).Returns(quantity);
return mock;
}
And this is the code under test:
public void AddItem(IShoppingCartItem item)
{
Enforce.ArgumentNotNull(item, "item");
var existingItem = this.Items.SingleOrDefault(x => x.Sku == item.Sku);
if (existingItem != null)
{
existingItem.Quantity += item.Quantity;
}
else
{
this.Items.Add(item);
}
}
I am getting this result: Test 'Titan.Tests.ShoppingCartTests.ShoppingCart_ShouldIncrementQuantity_WhenAddingDuplicateItem' failed: Expected 3, but found 1.
I am baffled or I am just having a dumb moment!
The problem here is that you haven't told Moq what to do when the Quantity property is set.
By default, Moq doesn't just assume that all of your properties should be simple getter/setters. It's up to you to decide what to do with them.
You have a couple of options.
Use SetupAllProperties() to tell Moq to treat properties as simple getter/setters.
private Mock<IShoppingCartItem> GetMockItem(string sku, decimal price = 10, int quantity = 1)
{
var mock = new Mock<IShoppingCartItem>();
mock.SetupAllProperties();
// Set the properties like normal properties. Moq will do the right thing.
mock.Object.Sku = sku;
mock.Object.Price = price;
mock.Object.Quantity = quantity;
return mock;
}
Use SetupSet to handle the case where the Quantity property is set, and in its callback, re-setup the property getter, so that it returns the new value.
private Mock<IShoppingCartItem> GetMockItem(string sku, decimal price = 10, int quantity = 1)
{
var mock = new Mock<IShoppingCartItem>();
mock.Setup(x => x.Sku).Returns(sku);
mock.Setup(x => x.Price).Returns(price);
mock.Setup(x => x.Quantity).Returns(quantity);
// You can call Setups from within Setups
mock.SetupSet(x => x.Quantity).Callback(q => mock.Setup(x => x.Quantity).Returns(q));
return mock;
}
Alternately, you could also change your design so that you aren't modifying public properties.
The mocked property of the first item is set up to always return 1. It doesn't matter you add 2 to it then, it will always return 1.
Edit: your += is ignored because your cart stores mocked objects. The one that gets to the cart first is mocked to ALWAYs returns 1.
With JustMock I can mock DataContext tables with lists in Linq to SQL easily like this, where an IEnumerable is taking the place of each DataContext's table through ReturnsCollection() allowing me to plug in fake data:
[TestMethod]
public void ShouldGetManagersByHireDate()
{
var context = Mock.Create<MyDataContext>();
Mock.Arrange(()=> context.Employees).ReturnsCollection(GetFakeEmployees());
Mock.Arrange(() => context.Managers).ReturnsCollection(GetFakeManagers());
var repository = new EmployeeRepository(context);
var managers = repository.GetManagersByHireDate(new DateTime(2002, 1, 1), DateTime.Now);
Assert.AreEqual(1, managers.Count());
Assert.AreEqual(1, managers.FirstOrDefault().ID);
}
private IEnumerable<Employee> GetFakeEmployees()
{
return new List<Employee> {
new Employee { ID = 1, HireDate = new DateTime(2004, 12, 1) },
new Employee { ID = 2, HireDate = new DateTime(2006, 7, 1) },
new Employee { ID = 3, HireDate = new DateTime(2009, 3, 1) }
};
}
private IEnumerable<Manager> GetFakeManagers()
{
return new List<Manager> {
new Manager { ID = 1 }
};
}
And this would be the method under test:
public IQueryable<Employee> GetManagersByHireDate(DateTime start, DateTime end)
{
return from e in context.Employees
join m in context.Managers on e.ID equals m.ID
where e.HireDate >= start && e.HireDate <= end
select e;
}
I am looking for some way of performing the same magic allowing me to use IEnumerable<T> in place of Table<T> for the purpose of testing Linq to SQL, preferably in FakeItEasy.
Linq to SQL isn't the easiest thing to test using open source tools. Hopefully, this approach may work for you.
FakeItEasy doesn't have a method exactly like JustMock's ReturnCollection that would allow you to mock out an ITable to return an IEnumerable. One option you have is to create a MockableTable similar to the one shown here. Then to populate your Table, you could have something like
private ITable<Employee> GetFakeEmployees() {
List<Employee> sampleData = /* fill it up with employees */
var employeeTable = new MockableTable<Employee>(null, sampleData.AsQuerable());
return employeeTable;
}
Also, FakeItEasy won't intercept the Employees property on the DataContext since it's a non virtual property on a concrete class. You could create a simple custom base class and have MyDataContext class derive directly from that.
public abstract class CustomDataContext : DataContext, ICustomDataContext {
}
public interface ICustomDataContext {
ITable<Employee> { get; }
}
The main point here is to leverage the interface for your mock. Then in your test method, you would have:
[TestMethod]
public void ShouldGetManagersByHireDate() {
var context = A.Fake<ICustomDataContext>();
A.CallTo(()=> context.Employees).Returns(GetFakeEmployees());
var repository = new EmployeeRepository(context);
var managers = repository.GetManagersByHireDate(new DateTime(2002, 1, 1), DateTime.Now);
Assert.AreEqual(1, managers.Count());
Assert.AreEqual(1, managers.FirstOrDefault().ID);
}
I haven't actually compiled this, but concept should be stable. Relying on the abstractions will make your code more testable and easier to mock.
Hope this helps somewhat.
The way I have done this using FakeItEasy is to add an interface to DataContext and use that as my dependency in my repos. E.g.
public interface IMyDataContext : IDisposable
{
IQueryable<Employee> Employees { get; }
// etc.
}
public partial class MyDataContext: IMyDataContext
{
IQueryable<Message> IMyDataContext.Employees
{
get { return this.Employees; }
}
// etc.
}
public class EmployeeRepository
{
public EmployeeRepository(IMyDataContext context)
{
// etc.
}
}
And in my test:
var context = A.Fake<IMyDataContext>();
A.CallTo(() => context.Employees).Returns(new[] { new Employee { Name = "John", Name = "Fred" }.AsQueryable());
var repository = new EmployeeRepository(context)
I don't think any considerations surrounding ITable are required.
Why is this test failing?
[TestMethod]
public void Can_show_next_event()
{
// Arrange
var eventsRepo = MockRepository.GenerateStub<IRepository<Event>>();
Event nextEvent = new Event{
ID = 2,
Title = "Test Event",
Date = DateTime.Now.AddDays(2)
};
eventsRepo.Stub(x => x.Find(y => y.Date > DateTime.Now))
.Return(nextEvent);
// Act
var controller = new EventsController(eventsRepo);
var result = controller.Index() as ViewResult;
// Assert
Assert.IsNotNull(result);
Assert.AreEqual("Details", result.ViewName);
}
The test fails on the last line, seem the Repository is not returning what I want it too.
here's the index action
public ActionResult Index()
{
var model = _eventsRepo.Find(x => x.Date > DateTime.Now);
return model != null ? View("Details", model) : View("NoEvents");
}
here's my generic repository interface
public interface IRepository<T> where T: class
{
IQueryable<T> GetAll();
IEnumerable<T> GetAll(Expression<Func<T, bool>> predicate);
T GetById(int id);
T Find(Expression<Func<T, bool>> predicate);
void Add(T item);
void Delete(T item);
void Save();
}
I'm new to mocking with rhino, what am I doing wrong?
Thanks in advance
Try adding .IgnoreParameters() on this line:
eventsRepo.Stub(x => x.Find(y => y.Date > DateTime.Now))
.IgnoreParameters()
.Return(nextEvent);
Two side notes: your function "T Find(Expression<Func<T,bool>> predicate)"
could just use a Predicate<T> instead of a Func<T,bool>. The two are basically the same.
If you don't already have it, get a copy of the book "The Art of Unit Testing" by Roy Osherove from Manning.
http://www.manning.com/osherove/
He provides several chapters worth of unit testing samples using Rhino.Mocks
i have just started using Moq ver (3.1) and i have read blogs and what not.... anyway... i guess until you makes your hand dirty you will not learn :)
okay here is what i'm testing...
var newProduct = new Mock<IPartialPerson>();
newProduct.SetupGet(p => p.FirstName).Returns("FirstName");
newProduct.SetupGet(p => p.MiddleName).Returns("MiddleName");
newProduct.SetupGet(p => p.LastName).Returns("LastName");
newProduct.SetupGet(p => p.EmailAddress).Returns("EmailAddress#hotmail.com");
newProduct.SetupGet(p => p.UserID).Returns("UserID");
//mock Escort repository
var mockEscortRepository = new Mock<IEscortRepository>();
mockEscortRepository.Setup(p => p.LoadAllEscorts())
.Returns(newProduct.Object); //error
Error 1 The best overloaded method
match for
'Moq.Language.IReturns>.Returns(System.Collections.Generic.List)'
has some invalid arguments
Error 2 Argument '1': cannot convert
from
'App.Model.Interface.IPartialPerson'
to
'System.Collections.Generic.List'
public interface IPartialPerson
{
string FirstName { get; }
string MiddleName { get; }
string LastName { get; }
string EmailAddress { get; }
string FullName { get; }
string UserID { get; }
}
public interface IEscortRepository
{
List<PartialPerson> LoadAllEscorts();
List<PartialPerson> SelectedEscorts(List<PartialPerson> selectedEscorts);
}
i have two methods that i want to test "LoadAllaEscorts" and "SelectedEscorts"
how would i do a test for both methods?
Try this:
mockEscortRepository
.Setup(p => p.LoadAllEscorts())
.Returns(new List<IPartialPerson>() { newProduct.Object } );
When you say:
.Returns(newProduct.Object)
You are asking Moq to return one specific object. The compiler sees that your method returns a list and so it will not compile unless you provide a list for it to return. So you need to create a list that contains the object you want to return then ask Moq to return that instead.
Based on your comments you might also be interested in testing a list with more than one item. To do that, create a list with more than one item, then ask the Mock to return that. Here is one way you could create a list with more than one item:
List<PartialPerson> escorts = new List<PartialPerson>();
for (int i = 0; i < 10; i++)
{
var escort = new Mock<IPartialPerson>();
escort.SetupGet(p => p.FirstName).Returns("FirstName" + i);
escort.SetupGet(p => p.MiddleName).Returns("MiddleName" + i);
escort.SetupGet(p => p.LastName).Returns("LastName" + i);
escort.SetupGet(p => p.EmailAddress).Returns(i + "EmailAddress#hotmail.com");
escort.SetupGet(p => p.UserID).Returns("UserID" + i);
escorts.Add(escort.Object);
}
mockEscortRepository
.Setup(p => p.LoadAllEscorts())
.Returns(escorts);
Good luck and keep on pimpin!
i have two methods that i want to test
"LoadAllaEscorts" and
"SelectedEscorts"
Those are methods on an interface. You don't write tests against an interface, or against mock objects. You write tests against concrete classes.
Somewhere you have an EscortRepository that implements IEscortRepository. I'm assuming that hits the database. Write integration tests against that.
Elsewhere in your code you probably have a class (call it "Foo") that has an IEscortRepository dependency injected into it (such as via a constructor parameter). When you want to write tests against the Foo class, you would use Moq to create a mock IEscortRepository returning fixed test data and pass that mock object into your Foo instance.
Another issue is that your IEscortRepository methods are returning (or taking as a parameter) List<PartialPerson>. Those should be IList<IPartialPerson> (or IEnumerable<T>, ICollection<T>, or ReadOnlyCollection<T>). The most important part is that the collection items should be an interface type (IPartialPerson).
+1 for magnifico, who had the code right:
using System;
using System.Collections.Generic;
using Moq;
namespace ConsoleApplication1
{
internal class Program
{
private static void Main(string[] args)
{
var newProduct = new Mock<IPartialPerson>();
newProduct.SetupGet(p => p.FirstName).Returns("FirstName");
newProduct.SetupGet(p => p.MiddleName).Returns("MiddleName");
newProduct.SetupGet(p => p.LastName).Returns("LastName");
newProduct.SetupGet(p => p.EmailAddress).Returns("EmailAddress#hotmail.com");
newProduct.SetupGet(p => p.UserID).Returns("UserID");
var mockEscortRepository = new Mock<IEscortRepository>();
mockEscortRepository
.Setup(p => p.LoadAllEscorts())
.Returns(new List<IPartialPerson> {newProduct.Object});
IEscortRepository repository = mockEscortRepository.Object;
IList<IPartialPerson> escorts = repository.LoadAllEscorts();
foreach (IPartialPerson person in escorts)
{
Console.WriteLine(person.FirstName + " " + person.LastName);
}
Console.ReadLine();
// Outputs "FirstName LastName"
}
}
public interface IPartialPerson
{
string FirstName { get; }
string MiddleName { get; }
string LastName { get; }
string EmailAddress { get; }
string FullName { get; }
string UserID { get; }
}
public interface IEscortRepository
{
IList<IPartialPerson> LoadAllEscorts();
IList<IPartialPerson> SelectedEscorts(IList<IPartialPerson> selectedEscorts);
}
}
(The above example is not a unit test; it just shows that Moq works.)
Note that you don't have to use SetupGet for properties; Setup works as well.
Your mock is setup to return a single item, and it should return a List according to the repository interface.