mock datareader failing on second call - unit-testing

In the test below, the mocked datareader returns the desired value the first time, but then returns the same value when the index should be 1.
Am I misusing the dataReader or Rhino stub syntax? What is the fix?
Cheers,
Berryl
failing test
[Test]
public void NullSafeGet_GetsBothProperties()
{
var sessionImplementor = MockRepository.GenerateStub<ISessionImplementor>();
var userType = new DateRangeUserType();
var reader = MockRepository.GenerateStub<IDataReader>();
var start = new DateTime(2011, 6, 1);
var end = new DateTime(2011, 7, 1);
reader.Stub(x => x[0]).Return(start);
reader.Stub(x => x[1]).Return(end); ***<==== returns Jun 1 instead of Jul1
var result = userType.NullSafeGet(reader, userType.PropertyNames, sessionImplementor, null);
Assert.That(result, Is.EqualTo(new DateRange(start, end, DateRange.MaxSupportedPrecision)));
}
Expected: <6/1/2011 12:00 AM - 7/1/2011 12:00 AM>
But was: <6/1/2011 12:00 AM - 6/1/2011 12:00 AM>
SUT (NHib CompositeUserType method)
public override object NullSafeGet(IDataReader dr, string[] names, ISessionImplementor session, object owner) {
if (dr == null) return null;
var foundStart = (DateTime)NHibernateUtil.DateTime.NullSafeGet(dr, names[0], session, owner);
var foundEnd = (DateTime)NHibernateUtil.DateTime.NullSafeGet(dr, names[1], session, owner);
var precision = DateRange.MaxSupportedPrecision;
var startDp = _getDatePoint(foundStart, precision);
var endDp = _getDatePoint(foundEnd, precision);
return new DateRange(startDp, endDp, precision);
}

You are not mocking everything that is called by NHibernate. This is roughly what NHibernate does with a reader:
...
int index = reader.GetOrdinal(name);
...
if (reader.IsDBNull(index)) {
return null;
} else {
...
val = rs[index];
...
}
Stub generated by Rhino will return 0 in response both GetOrdinal calls and it this is why it will return June1 both times. You can try to fix it by mocking GetOrdinal as well as indexer. Like this:
var reader = MockRepository.GenerateStub<IDataReader>();
var start = new DateTime(2011, 6, 1);
var end = new DateTime(2011, 7, 1);
reader.Stub(x => x.GetOrdinal(userType.PropertyNames[0])).Return(0);
reader.Stub(x => x.GetOrdinal(userType.PropertyNames[1])).Return(1);
reader.Stub(x => x[0]).Return(start);
reader.Stub(x => x[1]).Return(end);
But it might be worth reconsidering whether you really need to unit test UserType. It does not have a lot of responsibility other than calling NHibernate. Unit testing this class requires you to mock type you don't own (MS IDataReader). What's even worse is that this mock is used by another thirdparty (NHibernate). Essentially you need to look at NHibernate source code (which is what I did) to create a correct stub. Take a look at this article. It goes into a lot more details about why you should avoid mocking types that you don't own. You may be better off writing integration test for this class, using in-memory sqlite database.

Related

Using Spock to test Spring JdbcTemplate

I have the following Java 8 DAO method that uses Spring JdbcTemplate to hit a database:
class MyAppDao {
#Inject
DataSource dataSource
public List<String> getFizzByBuzzIds(List<Integer> buzzIds) {
String sql = "SELECT * from buzzes WHERE buzz_id IN ( :buzzIds )";
NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
Map<String, Object> paramValues = new HashMap<>(1);
paramValues.put("buzzIds", buzzIds);
List<Buzz> buzzes = jdbcTemplate.query(sql,
paramValues, (rs, rowNum) -> {
return new Buzz(rs.getString("buzz_id"), rs.getString("buzz_key"),
rs.getString("buzz_external_id"));
}
);
List<String> fizzes = figureOutSomehow();
return fizzes;
}
}
I cannot change the dependencies injected into this method. The NamedParameterJdbcTemplate instance must be defined inside this method. The only thing I can mock (easily) is the dataSource.
I am trying (and I know, the method isn't written to be conducive to unit tests at all!) to write a Spock unit test for this, and just want to verify that when getFizzByBuzzIds is called, that jdbcTemplate.query is called (with any arguments).
My best attempt:
def 'getFizzByBuzzIds attempts to get case info from the DB'() {
given:
MyAppDao dao = Spy(MyAppDao, constructorArgs: [ dataSource ]) {
getJdbcTemplate() >> Mock(JdbcTemplate) {
1 * query('', null) // ???
}
}
when:
List<Integer> buzzIds = [1, 2, 3, 4]
dao.getFizzByBuzzIds(buzzIds)
then:
1 * dao.jdbcTemplate.query('', null) // ???
}
How can I configure the Spy and the then block label so that executing getFizzByBuzzIds verifies whether the underlying JdbcTemplate.query(...) method is called?

Unit test a custom collection created by a lots of logic

I have a Factory class with a Create method that takes 8 parameters.
All these 8 parameters are used in combination inside the Create method.
The Create method returns a custom collection.
The custom collection as result needs to be compared to other collections somehow which I
have passed also to the Create method. But I can not make an 1:1 comparison of the custom
collection. I would have to filter,drill down , sort etc... things to get a successfull
Assert...
I know well about unit testing but I am clueless about testing such a scenario without bringing much logic into the Assertion itself what I actually want to avoid.
As the Create method returns a collection of "Days" for a calendar I can not do manual tests of single days I have to test the whole collection. Edge cases tests are not enough.
UPDATE
I put here a sample which is the easiest one of my samples that you get an understanding...
My other unit test (not done) will be way harder as my date range is bigger that means much
assertions and the logic to test increases.
[Test]
public void CreatePeriods_3TimeTablesWithin7VisibleDays_21Periods()
{
// ARRANGE
IDateService dateService = new DateService();
LessonplannerFactory factory = new LessonplannerFactory(dateService);
DateTime startDate = new DateTime(2013, 03, 01);
DateTime endDate = new DateTime(2013, 03, 15);
String schoolclassCode1 = "BIO1";
String schoolclassCode2 = "BIO2";
String schoolclassCode3 = "BIO3";
IEnumerable<TimeTable> timetableA = new List<TimeTable> {
new TimeTable { LessonNumber = 3, SchoolclassCodeMonday = schoolclassCode3, WeekTypeState = TimeTable.WeekType.A },
new TimeTable { LessonNumber = 2, SchoolclassCodeMonday = schoolclassCode2, WeekTypeState = TimeTable.WeekType.A },
new TimeTable { LessonNumber = 1, SchoolclassCodeMonday = schoolclassCode1, WeekTypeState = TimeTable.WeekType.A },
};
TimeTable.WeekType selectedWeekType = TimeTable.WeekType.A;
TimeTable.WeekType startWeekType = TimeTable.WeekType.A;
DayOfWeek firstDayOfWeek = DayOfWeek.Monday;
IEnumerable<DayOfWeek> visibleWeekDays = new List<DayOfWeek> { DayOfWeek.Friday, DayOfWeek.Sunday, DayOfWeek.Monday };
int numberOfVisibleDays = 7; int numberOfTimeTables = 3;
// ACT
var periods = factory.Create(startDate, endDate, 0, timetableA, null, selectedWeekType, startWeekType, firstDayOfWeek, visibleWeekDays);
// sort by both properties to make this unit test testable...
var sortedPeriods = periods.OrderBy(p => p.LessonNumber).ThenBy(p => p.LessonDate);
// ASSERT
Assert.IsTrue(periods.Count() == numberOfTimeTables * numberOfVisibleDays);
// LessonNumber 1
Assert.AreEqual(sortedPeriods.ElementAt(0).LessonNumber, 1);
Assert.AreEqual(sortedPeriods.ElementAt(1).LessonNumber, 1);
Assert.AreEqual(sortedPeriods.ElementAt(2).LessonNumber, 1);
Assert.AreEqual(sortedPeriods.ElementAt(3).LessonNumber, 1);
Assert.AreEqual(sortedPeriods.ElementAt(4).LessonNumber, 1);
Assert.AreEqual(sortedPeriods.ElementAt(5).LessonNumber, 1);
Assert.AreEqual(sortedPeriods.ElementAt(6).LessonNumber, 1);
Assert.AreEqual(sortedPeriods.ElementAt(0).SchoolclassCode, string.Empty);
Assert.AreEqual(sortedPeriods.ElementAt(1).SchoolclassCode, string.Empty);
Assert.AreEqual(sortedPeriods.ElementAt(2).SchoolclassCode, schoolclassCode1);
Assert.AreEqual(sortedPeriods.ElementAt(3).SchoolclassCode, string.Empty);
Assert.AreEqual(sortedPeriods.ElementAt(4).SchoolclassCode, string.Empty);
Assert.AreEqual(sortedPeriods.ElementAt(5).SchoolclassCode, schoolclassCode1);
Assert.AreEqual(sortedPeriods.ElementAt(6).SchoolclassCode, string.Empty);
Assert.AreEqual(sortedPeriods.ElementAt(0).LessonDate, new DateTime(2013, 03, 01));
Assert.AreEqual(sortedPeriods.ElementAt(1).LessonDate, new DateTime(2013, 03, 03));
Assert.AreEqual(sortedPeriods.ElementAt(2).LessonDate, new DateTime(2013, 03, 04));
Assert.AreEqual(sortedPeriods.ElementAt(3).LessonDate, new DateTime(2013, 03, 08));
Assert.AreEqual(sortedPeriods.ElementAt(4).LessonDate, new DateTime(2013, 03, 10));
Assert.AreEqual(sortedPeriods.ElementAt(5).LessonDate, new DateTime(2013, 03, 11));
Assert.AreEqual(sortedPeriods.ElementAt(6).LessonDate, new DateTime(2013, 03, 15));
// LessonNumber 2
// do the same as above
// LessonNumber 3
// do the same as above
}
It seems to me that you need to break up the code to "Create" into smaller pieces. Having so many parameters into the function is usually a sign of mixing too many pieces of functionality into one object.
If you can divide the work into smaller object, you can test each objects functionality easier, and then your higher level test can be used to just make sure that you are delegating the work to all of the smaller objects correctly.

Mock IDbDataAdapter Fill Method With Moq

I have an object that reads data from an Excel file using, which takes a IDbConnection, IDbDataAdapter and an IDbCommand. I use the adapters fill method to populate a table with data, and this is how I am currently mocking it:
[TestCase]
public void TestReadCellsFromSpreadsheetReadsSuccessfully()
{
var cells = new List<ReportData>
{
new ReportData { CellId = 1, ExcelCellLocation = "A1"},
new ReportData { CellId = 2, ExcelCellLocation = "A2"},
new ReportData { CellId = 3, ExcelCellLocation = "A3"},
new ReportData { CellId = 4, ExcelCellLocation = "A4"}
};
_mockAdapter.Setup(a => a.Fill(It.IsAny<DataSet>()))
.Callback((DataSet ds) =>
{
if (ds.Tables["Table"] == null)
{
ds.Tables.Add("Table");
ds.Tables["Table"].Columns.Add(new DataColumn());
}
var row = ds.Tables["Table"].NewRow();
row[0] = "Test";
ds.Tables["Table"].Rows.Add(row);
});
var excelReader = new ExcelReader(_mockConnection.Object, _mockAdapter.Object, _mockCommand.Object);
excelReader.ReadCellsFromSpreadsheet("Deal Summary", cells);
_mockCommand.VerifySet(c => c.CommandText = It.IsAny<string>(), Times.Exactly(cells.Count));
_mockAdapter.VerifySet(a => a.SelectCommand = _mockCommand.Object, Times.Exactly(cells.Count));
_mockAdapter.Verify(a => a.Fill(It.IsAny<DataSet>()), Times.Exactly(cells.Count));
}
This implementation works, but I feel like I'm doing too much to Mock the adapter... is there a better way to do this?
Do not pass those 3 objects as parameters. Instead pass IDataReader, IDataProvider or sth like that that returns data. Then You just mock this object. And you don't need reference to System.Data in project containing ExcellReader.
And two other things I don't like about your code.
Why TestCase instead of Test?
Are you sure you want to create command and fill dataset for each column separately? (but maybe I don't understand your code)
In general, I have some rules about data access:
Write a simple class that wraps all the data access logic, so that other classes don't have to deal with DataAdapters and all that crap.
When you write unit tests, don't mock out DataAdapters; instead just mock out the wrapper classes that you just created.
Make the data access wrapper logic so simple that it doesn't really need to be unit tested. If it DOES need to be tested, then write integration tests that hit a small sample database.

Using Moq to mock a repository that returns a value

How do I set up my test method on that mocks a repository which accepts an object?
This is what I have so far:
Service.cs
public int AddCountry(string countryName)
{
Country country = new Country();
country.CountryName = countryName;
return geographicsRepository.SaveCountry(country).CountryId;
}
test.cs
[Test]
public void Insert_Country()
{
//Setup
var geographicsRepository = new Mock<IGeographicRepository>();
geographicsRepository.Setup(x => x.SaveCountry(It.Is<Country>(c => c.CountryName == "Jamaica"))); //How do I return a 1 here?
GeographicService geoService = new GeographicService(geographicsRepository.Object);
int id = geoService.AddCountry("Jamaica");
Assert.AreEqual(1, id);
}
SaveCountry(Country country); returns an int.
I need to do 2 things:
First test, I need to tell the setup to return an int of 1.
I need to create a second test Insert_Duplicate_Country_Throws_Exception(). In my Setup, how do I tell the repository to throw an error when I do:
int id = geoService.AddCountry("Jamaica");
int id = geoService.AddCountry("Jamaica");
Framework:
NUnit.
Moq.
ASP.NET MVC - repository pattern.
Your first test should look something like this:
[Test]
public void Insert_Country()
{
Mock<IGeographicRepository> geographicsRepository = new Mock<IGeographicRepository>();
GeographicService geoService = new GeographicService(geographicsRepository.Object);
// Setup Mock
geographicsRepository
.Setup(x => x.SaveCountry(It.IsAny<Country>()))
.Returns(1);
var id = geoService.AddCountry("Jamaica");
Assert.IsInstanceOf<Int32>(id);
Assert.AreEqual(1, id);
geographicsRepository.VerifyAll();
}
The second test should look like this:
[Test]
public void Insert_Duplicate_Country_Throws_Exception()
{
Mock<IGeographicRepository> geographicsRepository = new Mock<IGeographicRepository>();
GeographicService geoService = new GeographicService(geographicsRepository.Object);
// Setup Mock
geographicsRepository
.Setup(x => x.SaveCountry(It.IsAny<Country>()))
.Throws(new MyException());
try
{
var id = geoService.AddCountry("Jamaica");
Assert.Fail("Exception not thrown");
}
catch (MyException)
{
geographicsRepository.VerifyAll();
}
}
I think maybe you are slightly misunderstanding the purpose of testing with mocks in the two scenarios you have supplied.
In the first scenario, you wish to test that 1 is returned when you pass in "Jamaica". This is not a mock test case but a test case for real behaviour as you wish to test a specific input against an expected output i.e. "Jamaica" -> 1. In this situation mocking is more useful to ensure that internally your service calls SaveCountry on the repository with the expected country, and that it returns the value from the call.
Setting up your "SaveCountry" case and then calling "VerifyAll" on your mock is the key. This will assert that "SaveCountry" was indeed called with country "Jamaica", and that the expected value is returned. In this way you have confidence that your service is wired up to your repository as expected.
[Test]
public void adding_country_saves_country()
{
const int ExpectedCountryId = 666;
var mockRepository = new Mock<IGeographicRepository>();
mockRepository.
Setup(x => x.SaveCountry(It.Is<Country>(c => c.CountryName == "Jamaica"))).
Returns(ExpectedCountryId);
GeographicService service= new GeographicService(mockRepository.Object);
int id = service.AddCountry(new Country("Jamaica"));
mockRepo.VerifyAll();
Assert.AreEqual(ExpectedCountryId, id, "Expected country id.");
}
In the second scenario you wish to test that an exception is raised when you attempt to add a duplicate country. There's not much point in doing this with a mock as all you will test is that your mock has behaviour when adding duplicates, not your real implementation.

Moq - How to unit test changes on a reference in a method

Another day , another question. My service layer has the following method
public MatchViewData CreateMatch(string user)
{
var matchViewData = !HasReachedMaxNumberOfMatchesLimit(user) ?
CreateMatchAndAddToRepository(user) :
MatchViewData.NewInstance(new Match(user));
matchViewData.LimitReached = HasReachedMaxNumberOfMatchesLimit(user);
return matchViewData;
}
The method calls the this helper method to create a new match object:
private MatchViewData CreateMatchAndAddToRepository(string user)
{
var match = new Match(user);
MatchRepository.Add(match);
return MatchViewData.NewInstance(match);
}
The repository stores the given match object and sets the id to some value > 0.
public void Add(Match match)
{
Check.Require(match != null);
var numberOfMatchesBefore = Matches.Count;
SetIdPerReflection(match, NextVal());
Matches.Add(match);
Check.Ensure(numberOfMatchesBefore == Matches.Count - 1);
}
The matchviewdata object copies some properties of the the match object (including the id).
My unit test should verify that the resulting viewdata object in the service has an id > 0. To archieve this, i have to mock the repository and the behaviour of the add method. But the service method creates a new match object every time its been called and the add method on the repository updates the referenced match object (there is no need for a return value). I have no idea to solve this with moq.
This is my unit test so far:
[Test]
public void ServiceCreateMatchReturnedMatchViewDataHasNonZeroId()
{
var match = TestUtils.FakePersistentMatch(User, 1);
var repositoryMock = new Mock<IMatchRepository>();
repositoryMock.Setup(
r => r.Add(It.IsAny<Match>())).Callback(() => match.Id = 1);
var serviceFacade = new DefaultServiceFacade(repositoryMock.Object);
var returnedMatch = serviceFacade.CreateMatch(User);
Assert.That(returnedMatch.Id, Is.GreaterThan(0));
}
I tried some other variations - nothing works.
It looks to me your problem is in this line;
repositoryMock.Setup(
r => r.Add(It.IsAny<Match>())).Callback(() => match.Id = 1);
What you're actually doing here is setting the id of the first match object you have declared in your test, NOT the new match created in your service.
Because the Match object you will be supplying to the Repository is created internally, I can't think of an easy way to reference it in your Test method to setup a callback for it. To me, this is a sign you may be trying to test too much in one unit test.
I think you should simply test that the Add method is called and write a separate test to ensure that it works as exepected.
I propose something like this;
[Test]
public void ServiceAddsNewMatchToRepository()
{
var repositoryMock = new Mock<IMatchRepository>();
bool addCalled = false;
repositoryMock
.Expect(r => r.Add(It.Is<Match>(x => x.Id == 0))
.Callback(() => addCalled = true);
var serviceFacade = new DefaultServiceFacade(repositoryMock.Object);
serviceFacade.CreateMatch(User);
Assert.True(addCalled);
}
....
[Test]
public void AddingANewMatchGeneratesANewId()
{
var match = new Match(user);
var matchRepository = new MatchRepository();
var returnedMatch = matchRepository.Add(match);
Assert.That(returnedMatch.Id, Is.GreaterThan(0));
}