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.
Related
I have a method that validate an Object calling an external service:
public void Validate(IValidator<MyType> validator)
{
IMapper<MyType> mapper = new MyTypeMapper();
foreach (var element in this.Elements)
{
ValidationResult result = validator.Validate(myTypeInstance, mapper, new ValidationConfiguration());
if (result.IsValid)
// do something
else
// do something else
}
}
Now in my unit test I have a collection of elements. And I want that if an element have a given id number the Validate method should return another stub with validation messages:
// arrange
var myAggregate aggregate = ElementsNonValidated.Stub();
var mockedValidator = new Mock<IValidator<MyType>>();
mockedValidator.Setup(a => a.Validate(
It.Is<Mytype>(x => x.Id == Guid.Parse("3F2504E0-4F89-11D3-9A0C-0305E82C3301")),
new Mapper(),
new ValidationConfiguration()
)).Returns<ValidationResult>(x => x = new ValidationResult());
// act
myAggregate.Valida(mockedValidator.Object);
The problem is: When unit test starts and go forth till the real method validate still return result=null. Why? What's wrong with my mock?
The problem is here:
mockedValidator.Setup(a => a.Validate(
It.Is<Mytype>(x => x.Id == Guid.Parse("3F2504E0-4F89-11D3-9A0C-0305E82C3301")),
new Mapper(),
new ValidationConfiguration()
)).Returns<ValidationResult>(x => x = new ValidationResult());
You setup Validate to expect specific Mapper and ValidationResult instances, which of course do not match the instances used in your system under test. If you don't care what instance should be used for a parameter, use It.IsAny<>:
mockedValidator.Setup(a => a.Validate(
It.Is<Mytype>(x => x.Id == Guid.Parse("3F2504E0-4F89-11D3-9A0C-0305E82C3301")),
It.IsAny<Mapper>(),
It.IsAny<ValidationConfiguration>()
)).Returns<ValidationResult>(x => x = new ValidationResult());
This will return a new ValidationResult for any and every invocation to Validate where the object's Id is equal to that particular GUID.
The reason for the TargetParameterCountException is in your Returns statement, and is answered here.
I am trying to deploy some code that does something simple, when the user clicks on the accept button, it checks a checkbox (I have a workflow set up on the checkbox) and then I need it to redirect me to a thank you page. At the moment I don't know if my code is correct so I need to get the test correct to test it.
My Apex class:
public class proposalCon {
ApexPages.StandardController stdCtrl;
Public List <PPM_Project__c> PPM_Project_List {get;set;}
public proposalCon(ApexPages.StandardController controller) {
stdCtrl= controller;
PPM_Project_List = [ select Short_Description__c from PPM_Project__c ];
}
public PageReference save(){
upsert PPM_Project_List;
PageReference reRend = new PageReference('/apex/final_approval_canvas_complete');
reRend.setRedirect(true);
return reRend;
}
}
And here is my test attempt:
#isTest
private class proposalConTest{
static testMethod void testProposalCon() {
// List of Message
List <PPM_Project__c> PPM_ProjectList = new List<PPM_Project__c>();
PPM_ProjectList.add(new PPM_Project__c (
Name = 'A Test' ,
Short_Description__c = 'Good Job',
Due_Date__c = system.today()+30,
Final_Design_Artwork__c ='http://proteusleadership.com/DE123'
));
PPM_ProjectList.add(new PPM_Project__c (
Name = 'A Test 2' ,
Short_Description__c = 'Good Job',
Due_Date__c = system.today()+30,
Final_Design_Artwork__c ='http://proteusleadership.com/DEf123'
));
insert PPM_ProjectList;
Account account = new Account(Name='Test Co Pty Ltd');
insert account;
Contact contact = new Contact(firstName='TestFN',LastName='TestLN',email='testfn.testln#test.com',AccountId=account.Id);
insert contact;
// ** Start Testing ***/
proposalCon controller = new proposalCon();
PageReference reRend = new PageReference('/apex/final_approval_canvas_complete');
reRend.setRedirect(true);
PPM_ProjectList = [ select Short_Description__c from PPM_Project__c ];
}
}
I have been trying with no luck and any help would be greatly appreciated.
Thank you.
Joe
You need to instantiate a Standard Controller (feeding it a list of PPM Projects) and then instantiate your custom controller extension - like this:
PPM_Project__c proj = new PPM_Project__c() //you may need further parameters here.
ApexPages.StandardController stdController = new apexPages.StandardController(proj);
proposalCon controller = new proposalCon (stdController);
Then you can save, rerender as you like. Let me know if this works - I haven't executed this code, but this is how I create my own controller extension tests.
This should at least compile. However, I think you may really want a StandardSetController.
The docs are here:
SalesforceDocs
To make a testmethod for the StandardSetController, use something like this:
//instantiate the ApexPages.StandardSetController with an array of projects
ApexPages.StandardSetController stdSetController = new ApexPages.StandardSetController(PPM_ProjectList);
//create custom controller with the StandardSetController as a param
ProposalCon ext = new ProposalCon(stdSetController);
This guy has more details on how to create a test method for a StandardSetController (and other controllers)
I'm trying to set up a stub with Rhino Mocks which returns a value based on what the parameter of the argument that is passed in.
Example:
//Arrange
var car = new Car();
var provider= MockRepository.GenerateStub<IDataProvider>();
provider.Stub(
x => x.GetWheelsWithSize(Arg<int>.Is.Anything))
.Return(new List<IWheel> {
new Wheel { Size = ?, Make = Make.Michelin },
new Wheel { Size = ?, Make = Make.Firestone }
});
car.Provider = provider;
//Act
car.ReplaceTires();
//Assert that the right tire size was used when replacing the tires
The problem is that I want Size to be whatever was passed into the method, because I'm actually asserting later that the wheels are the right size. This is not to prove that the data provider works obviously since I stubbed it, but rather to prove that the correct size was passed in.
How can I do this?
"This is not to prove that the data provider works ... but rather to prove that
the correct size was passed in."
Not sure if it works that well for this particular case, but generally I've found it easiest to test these sorts of things indirectly via the stub.
Rather than checking the output of the stubbed call, explicitly specify the arguments to your stub and then verify that the return value was used as expected (regardless of the actual data returned). If it was, then you know that your stub was called correctly.
//Arrange
var wheels = new List<IWheel>();
const int wheelSize = 17;
var car = new Car();
car.WheelSize = wheelSize;
var provider= MockRepository.GenerateStub<IDataProvider>();
provider
.Stub(x => x.GetWheelsWithSize(wheelSize))
.Return(wheels);
car.Provider = provider;
//Act
car.ReplaceTires();
//Assert that the right-sized wheels from the provider were
//used when replacing the tires
Assert.That(car.Wheels, Is.SameAs(wheels));
If this approach doesn't work for you in this case then you can use WhenCalled to inspect the call arguments and/or modify the return value.
provider
.Stub(x => x.GetWheelsWithSize(Arg<int>.Is.Anything))
.WhenCalled(x => x.ReturnValue = CreateWheelsOfSize((int) x.Arguments[0]));
In this case CreateWheelsOfSize(int) will just create your list of wheels.
Hope this helps.
You can use the Do() functionality in order to achieve dynamic return value. For example:
[Test]
public void DynamicallyFakeReturnValue()
{
var calculatorStub = MockRepository.GenerateStub<ICalculator>();
calculatorStub.Stub(address => address.AddOne(Arg<int>.Is.Anything))
.Do((Func<int, int>) (x => x - 1));
Assert.That(calculatorStub.AddOne(1), Is.EqualTo(0));
}
In your case it will probably be:
provider.Stub(
x => x.GetWheelsWithSize(Arg<int>.Is.Anything))
.Do((Func<int, List<IWheel>>) (size => new List<IWheel> {
new Wheel { Size = size, Make = Make.Michelin },
new Wheel { Size = size, Make = Make.Firestone }
}));
I'm using Rhino Mocks to try to verify that when I call a certain method, that the method in turn will properly group items and then call another method.
Something like this:
//Arrange
var bucketsOfFun = new BucketGame();
var balls = new List<IBall>
{
new Ball { Color = Color.Red },
new Ball { Color = Color.Blue },
new Ball { Color = Color.Yellow },
new Ball { Color = Color.Orange },
new Ball { Color = Color.Orange }
};
//Act
bucketsOfFun.HaveFunWithBucketsAndBalls(balls);
//Assert ???
Here is where the trouble begins for me. My method is doing something like this:
public void HaveFunWithBucketsAndBalls(IList<IBall> balls)
{
//group all the balls together according to color
var blueBalls = GetBlueBalls(balls);
var redBalls = GetRedBalls(balls);
// you get the idea
HaveFunWithABucketOfBalls(blueBalls);
HaveFunWithABucketOfBalls(redBalls);
// etc etc with all the different colors
}
public void HaveFunWithABucketOfBalls(IList<IBall> colorSpecificBalls)
{
//doing some stuff here that i don't care about
//for the test i'm writing right now
}
What I want to assert is that each time I call HaveFunWithABucketOfBalls that I'm calling it with a group of 1 red ball, then 1 blue ball, then 1 yellow ball, then 2 orange balls.
If I can assert that behavior then I can verify that the method is doing what I want it to do, which is grouping the balls properly.
Any ideas of what the best testing pattern for this would be?
One way to test this is to break out the responsibility of working with a colour-specific balls to a dependency, say, IBucketHandler:
//Arrange
var bucketHandler = MockRepository.GenerateStub<IBuckerHandler>();
var bucketsOfFun = new BucketGame(bucketHandler);
...
//Assert
bucketHandler.AssertWasCalled(x => x.HaveFunWithABucketOfBalls(redBalls));
bucketHandler.AssertWasCalled(x => x.HaveFunWithABucketOfBalls(greenBalls));
This test is then checking your BucketGame correctly calls HaveFunWithABucketOfBalls on the mocked object. This may still give you trouble in specifying what each argument should be. You can in turn make this easier to test (at the expense of introducing more abstraction) by pushing the responsibility for sorting the balls to a new dependency. You'd then end up with something like this:
//Arrange
var balls = new List<IBall>(); //Can really be anything, we just need the object reference
var greenBalls = new List<IBall>();
var redBalls = new List<IBall>();
var sortedBalls = new [] { greenBalls, redBalls };
var bucketHandler = MockRepository.GenerateStub<IBucketHandler>();
var ballSorter = MockRepository.GenerateStub<IBallSorter>();
ballSorter.Stub(x => x.Sort(balls)).Return(sortedBalls);
var bucketsOfFun = new BucketGame(bucketHandler, ballSorter);
//Act
bucketsOfFun.HaveFunWithBucketsAndBalls(balls);
//Assert
bucketHandler.AssertWasCalled(x => x.HaveFunWithABucketOfBalls(greenBalls));
bucketHandler.AssertWasCalled(x => x.HaveFunWithABucketOfBalls(redBalls));
And to pass this test, in BucketGame:
public BucketGame(IBucketHandler bucketHandler, IBallSorter ballSorter)
{
this.bucketHandler = bucketHandler;
this.ballSorter = ballSorter;
}
public void HaveFunWithBucketsAndBalls(IList<IBall> balls)
{
//group all the balls together according to color
var sortedBalls = ballSorter.Sort(balls);
foreach (var groupOfBalls in sortedBalls)
{
bucketHandler.HaveFunWithABucketOfBalls(groupOfBalls);
}
}
This tests the BucketGame logic. You'll now want to write unit tests for an IBallSorter implementation to check that it sorts the balls by colour as you require. Those tests probably won't need any mocking, you'll simply be able to throw data in and assert that the data you get back is what you expect.
the first thing you need to sort out in any test is what exactly your Subject Under Test is. that might sound gratuitous but I know from my own experiences that this can be confusing when you are learning interaction testing.
the reason I am guessing this is part of the problem is that you have an IBall object, but you want to asserts calls being made on a method that doesn't appear to be part of an interface. As you know, Rhino does it's magic by overriding something virtual, like an interface; so if you want to use to Rhino to do this you have to give it an interface. Assuming that is the case, maybe
interface IBucketGame{
void HaveFunWithBucketsAndBalls(IList<IBall> balls)
void HaveFunWithSpecificBalls(IList<IBall> balls)
}
Now you can set up an interaction test:
[Test]
public void HaveFunWithBucket_IfMoreThanOneColor_CallsHaveFunWithSpecificBallsForSpecificColor()
{
//Arrange
var bucketsOfFun = MockRepository.GenerateMock<IBucketGame>();
IBall expColor_1 = new Ball(Color.Red);
IBall expColor_2 = new Ball(Color.Green);
IBall expColor_3 = new Ball(Color.Red);
var startlist = new List<IBall>{expColor_1, expColor_2, expColor_3};
var onlyRedBalls = new List<IBall>{expColor_1, expColor_3};
var onlyGreenBalls = new List<IBall>{expColor_2};
//Act
bucketsOfFun.HaveFunWithBucketsAndBalls(balls);
//Assert
bucketsOfFun.AssertWasCalled(x=>x.HaveFunSpecificBalls(Arg<IEnumerable<IBall>>.List.Equal(onlyRedBalls)));
bucketsOfFun.AssertWasCalled(x=>x.HaveFunSpecificBalls(Arg<IEnumerable<IBall>>.List.Equal(onlyGreenBalls)));
}
HTH,
Berryl
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));
}