Mechanics of testing with a mock database connection - unit-testing

I have this application with a database on its back-end, and I'm having a lot of trouble wrapping my head around how to test this thing. (It's an Android app, but I think that the testing concepts are similar. In my application under test, I have a database adapter:
public class MyDatabaseAdapter() {
Cursor returnCursorFromQuery(SQLQuery query) {
// execute an SQL query and wrap the result in a Cursor object
}
}
I have a method, and I'm trying to test that it gives the right output when my database SELECT query returns no rows:
MyDatabaseAdapter adapter;
public int methodUnderTest() {
this.adapter = new MyDatabaseAdapter();
return populate();
}
private int populate() {
SQLQuery query = new SQLQuery("SELECT * FROM my_table");
Cursor aCursor = this.adapter.returnCursorFromQuery(query);
// populate the UI
return aCursor.getCount();
}
I have a mock cursor object that returns zero rows against all queries in my testing framework, what I don't understand is how I get my private populate() method to run its query against the mock cursor object rather than the cursor connected to my actual database. Or if I write a mock database adapter object, how to I get the methodUnderTest() to use the mock adapter instead of the one that it's programmed to use?
Any direction would be really helpful. Thanks.

You can make MyDatabaseAdapter implement an IDatabaseAdapter interface, and then create a mock MockDatabaseAdapter that returns what you want to test. Then instead of setting this.adapter = new MyDatabaseAdapter(); in MethodUnderTest set this.adapter in the constructor of the class, from a passed-in parameter of type IDatabaseAdapter:
public MyClass(IDatabaseAdapter adapter)
{
this.adapter = adapter;
}
Then you can pass in new MyDatabaseAdapter() in the production code and an instance of the mock class in the unit tests.

Related

Moq out parameters

I'm fairly new to using Moq and Nunit for unit testing and I'm having issues with one scenario. What I want is for my mock to have an out parameters which my system under test will then use to decide what action to take.
My system under test is an MVC API controller and in particular I'm trying to test the POST method. I want to return an error message for the object when validation fails.
Here is the method code for the controller:
public IHttpActionResult Post(Candidate candidate)
{
try
{
if(candidate==null)
return BadRequest();
IEnumerable<string> errors;
_candidateManager.InsertCandidate(candidate, out errors);
if (errors!=null && errors.Any())
return BadRequest(CreateErrorMessage("Invalid candidate: ", errors));
return CreatedAtRoute("DefaultApi", new {id = candidate.CandidateId}, candidate);
}
catch (Exception)
{
return InternalServerError();
}
}
This is my Unit Test Code:
[Test]
[Category("CandidateManagerController Unit Tests")]
public void Should_Return_Bad_Request_When_Creating_Invalid_Candidate()
{
IEnumerable<string> errors = new List<string>() {"error1", "error2"};
var mockManager = new Mock<ICandidateManager>();
mockManager.Setup(x => x.InsertCandidate(new Candidate(), out errors)).Callback(()=>GetErrors(errors));
var sut = new CandidateManagerController(mockManager.Object);
var actionResult = sut.Post(new Candidate());
Assert.IsInstanceOf<BadRequestResult>(actionResult);
}
What I expect is that when _candidateManager.InsertCandidate() is run then the errors variable is populated. However what is happening is that when you step through the controller code errors is null after _candidateManager.InsertCandidate() method is run.
If anyone has any ideas what I'm doing wrong or if what I want to do is not possible using Moq then please let me know.
Thanks
What you want to do is possible. If you look at the Quickstart docs at https://github.com/Moq/moq4/wiki/Quickstart, there is a section where it shows how you do setups for methods using out params. I have made two corrections to your code and it works.
You have to use the same candidate instance for both the mock setup and when you exercise the sut. Otherwise, Moq thinks that the two objects are different and your test setup becomes useless.
You don't have to use Callback in order to set the errors returned by the mocked CandidateManager.
Below is your test method with my changes.
[Test]
[Category("CandidateManagerController Unit Tests")]
public void Should_Return_Bad_Request_When_Creating_Invalid_Candidate()
{
IEnumerable<string> errors = new List<string>() {"error1", "error2"};
//instance to be used for both setup and test later
var candidate = new Candidate();
var mockManager = new Mock<ICandidateManager>();
//removed Callback
mockManager.Setup(x => x.InsertCandidate(candidate, out errors));
var sut = new CandidateManagerController(mockManager.Object);
var actionResult = sut.Post(candidate);
Assert.IsInstanceOf<BadRequestResult>(actionResult);
}
You have to make sure that when you call your SUT that you use the same instance passed to the out argument otherwise the call will fail.
In your example, the method under test passes a null instance into the mocked method thus negating the setup of the test.
If however you are not able to supply the same instances for the out then it doesn't look like you will be able to get a mock to pass successfully. Take a look a the Quick Start for Moq to get an understanding of it capabilities.

Mocking a REST Datasource in a Model TestCase for CakePHP

I am using the CakePHP-ReST-DataSource-Plugin Datasource for hitting a RESTful service in my model. This implies that the models will not have a database connection.
I have successfully accessed the services and would now like to write unit tests for the models. This is proving to be a daunting task since I cannot succeed to mock the datasource so that I do not hit the actual remote Service but rather return expected results for the tests.
<?php
App::uses('KnowledgePoint', 'Model');
class KnowledgePointTest extends CakeTestCase{
public $fixtures = array('app.knowledgepoint');
public $useDbConfig = 'RestTest';
private $KnowledgePoint;
public function setUp() {
parent::setUp();
$this->KnowledgePoint = ClassRegistry::init('KnowledgePoint');
/**
* This is the confusing part. How would I mock the datasource
so that I can mock the request method which returns the data
from the api?
*/
$this->KnowledgePoint->DataSource = $this->getMockForModel(
'RestSource',array('request'));
}
public function tearDown() {
parent::tearDown();
}
}
I would like to be able to mock the datasource and stub the request method to return data that would normally be returned from the remote service.
Kind regards,
Roland
Mocking the model and its getDataSource() method so that it returns your mocked datasource should theoretically work. Here's an example
App::uses('RestSource', 'Rest.Model/Datasource');
$DataSource = $this->getMock('RestSource', array('request'), array(array()));
$DataSource
->expects($this->any())
->method('request')
->will($this->returnValue('some custom return value'));
$Model = $this->getMockForModel('KnowledgePoint', array('getDataSource'));
$Model
->expects($this->any())
->method('getDataSource')
->will($this->returnValue($DataSource));
$Model->save(/* ... */);
In case you are wondering about the array(array()) for the datasource mock, this is required as the RestSource constructor doesn't supply a default value for the first argument (unlike the parent constructor).

How do I mock local variables of a mocked class in a Spock test?

Let's say I have the following method in a service:
private void deleteItems(List<Item> itemsToDelete) {
def sql = new Sql(dataSource)
itemsToDelete?.each { Item item ->
sql.execute("DELETE FROM owner_item WHERE item_id = ${item.id}")
item.delete(flush: true, failOnError: true)
flushDatabaseSession();
}
}
How do I create a test for this method in the ItemServiceSpec? When I try it, I get either a DataSource "Must specify a non-null Connection" error or a nullPointerException on sql.
This is my existing test.
#TestFor(ItemService)
#Mock([Item])
#Build([Item])
class SubjectServiceSpec extends Specification {
...
def "delete items"() {
given:
Item item1 = Item.build().save(flush: true)
Item item2 = Item.build().save(flush: true)
Item.count() == 2
DataSource mockDataSource = Mock()
service.dataSource = mockDataSource
1 * deleteItems
when:
service.deleteItems([item1, item2])
then:
Item.count() == 0
}
}
What you are trying to do here, is to mock a dependency (DataSource) of a dependency (Sql). This normally leads to a situation, where you a not 100% aware of how the Sql interacts with the DataSource Object. If Sql changes private interaction with the Datasource in a Version Update, you have to deal with the situation.
Instead of mocking a dependency of a dependency you should the Sql Class directly. For this, the sql has to be some kind of explicit dependency that you can receive via DI or a method parameter. In this case you can just mock the execute call like so (choosen the way of a Expando-Mock, but you could also use Map or the Mock Stuff from Spock):
given:
def sqlMock = new Expando()
sqlMock.execute = { return 'what ever you want or nothing, because you mock a delete operation' }
service.sql = sqlMock
when:
service.deleteItems([item1, item2])
then:
assertItemsAreDeletedAndTheOwnerAsWell()
Thinking about the whole testcase, there a two major problems in my opinion.
The first one is, when you ask yourself what kind of certainty do you really get here by mocking out the whole sql stuff. In this case, the only thing that you are doing here is to interact with the db. When you mock this thing out, then there is nothing anymore that you could test. There is not many conditional stuff or anything that should be backed up by a unit test. Due to this, I would suggest to write only integration spec for this test-case where you have something like a H2DB for testing purposes inplace.
The second thing is, that you actually don't need the Sql Manipulation at all. You can configure GORM and Hibernate in a way do a automatic and transparent deletion of the owner of the item, if the item is deleted. For this, look at the docs (especially the cascade part) from GORM or directly in the Hibernate docs.
To sum it up: use cascade: 'delete' together with a proper integration test and you have a high amount of certainty and less boilerplate code.

Moq - how to mock the result of a method within a method begin tested

and thank you in advance for any and all your assistance.
I have a method that I'm trying to test.
Within this method is a call to UserMembership.Validate()
//custom override but the code isn't functional yet and is outside the scope of the test.
I want to therefore mock (using moq) the return result so that the actual test of the method can succeed.
Here is the code
public LoginResponse Login(LoginRequest request)
{
var response = new LoginResponse(request.RequestId);
// Validate client tag and access token
if (!ValidateRequest(request, response, Validate.ClientTag | Validate.AccessToken))
return response;
if (!UserMembership.ValidateUser(request.UserName, request.Password))
{
response.Acknowledge = AcknowledgeType.Failure;
response.Messages = "Invalid username and/or password.";
//response.MessageCode = -4;
return response;
}
_userName = request.UserName;
return response;
}
So, my test is for LoginResponse() but I want to 'fake' the UserMembership return value (bool) to true...
Simple enough I'm sure for you guys.
TIA, Hugh.
You could probably re-title your question to "How do you use a mocking framework with unit testing 99% of the time," because you're right on track for doing just that - a very typical usage.
You're going to want to extract an interface from your UserMembership class (right click inside the class, select "refactor" and then "extract interface."), then use Moq to create mock instances of that interface for use within your tests. Then you can use Moq to "setup" the behavior of that mock to do anything you want it to during your test. The syntax would look like this:
var userMembershipMock = new Mock<IUserMembership>();
userMembershipMock.Setup(m=> m.ValidateUser(It.Is<string>(str=> str == "myUserName"), It.Is<string>(str=> str == "myPassword"))).Returns(true);
Then you would create a new instance of your class, passing in your mock instance of IUserMembership (but since you'll make your class's constructor takes an argument of the interface type, your class won't care whether you're passing it a mock or an actual UserMembership instance
MyClass myClass = new MyClass(userMembershipMock.Object);
after which you could begin actually testing the behavior of your MyClass:
var request = new LoginRequest { UserName = "myUserName", Password = "myPassword" };
LoginResponse response = myClass.Login(request);
And then you can assert that your class's response is what you expect:
Assert.AreEqual(AcknowledgeType.Success, response.Acknowledge);
or you can verify that your mock's method (or property) was invoked as you expected:
userMembershipMock.Verify(m=> m.ValidateUser(It.Is<string>(str=> str == "myUserName"), It.Is<string>(str=> str == "myPassword")), Times.Once());
and so on.
The Moq quick start page is kind of sort of a one-page read, and can teach you 99% of everything that you need to know to use it.
The only way I can think of to mock UserMembership in this case (assuming it's not a property) is to use an IoC framework like Castle Windsor or Ninject. When you use an IoC container you would refactor your calls to UserMembership into an interface (IUserMembership) and use the container to provide an implementation:
if (Container.Resolve<IUserMembership>().ValidateUser(request.UserName, request.Password))
Then in your unit test Setup you would register the implementation of IUserMembership to be the mock object:
var mock = new Mock<IUserMembership>();
Container.Register<IUserMemberhip>().Instance(mock.Object);
You would have to also create a production implementation. If this is the standard UserMembership class, this implementation will probably do nothing other than UserMembership. Although, there are other ways to mimic this kind of duck typing.

AbstractTransactionalJUnit4SpringContextTests: can't get the dao to find inserted data

I'm trying to set up integration tests using the AbstractTransactionalJUnit4SpringContextTests base class. My goal is really simple: insert some data into the database using the simpleJdbcTemplate, read it back out using a DAO, and roll everything back. JPA->Hibernate is the persistence layer.
For my tests, I've created a version of the database that has no foreign keys. This should speed up testing by reducing the amount of fixture setup for each test; at this stage I'm not interested in testing the DB integrity, just the business logic in my HQL.
/* DAO */
#Transactional
#Repository("gearDao")
public class GearDaoImpl implements GearDao {
#PersistenceContext
private EntityManager entityManager;
/* Properties go here */
public Gear findById(Long id) {
return entityManager.find(Gear.class, id);
}
}
/* Test Page */
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"/com/dom/app/dao/DaoTests-context.xml"})
#TransactionConfiguration(transactionManager="transactionManager", defaultRollback=false)
public class GearDaoImplTests extends AbstractTransactionalJUnit4SpringContextTests {
#Autowired
private GearDao gearDao;
#Test
#Rollback(true)
public void quickTest() {
String sql;
// fields renamed to protect the innocent :-)
sql = "INSERT INTO Gear (Gear_Id, fld2, fld3, fld4, fld5, fld6, fld7) " +
" VALUES (?,?,?,?,?,?,?)";
simpleJdbcTemplate.update(sql, 1L, 1L, 1L, "fld4", "fld5", new Date(), "fld7");
assertEquals(1L, simpleJdbcTemplate.queryForLong("select Gear_Id from Gear where Gear_Id = 1"));
System.out.println(gearDao);
Gear gear = gearDao.findById(1L);
assertNotNull("gear is null.", gear); // <== This fails.
}
}
The application (a Spring MVC site) works fine with the DAO's. What could be happening? And where would I begin to look for a solution?
The DAO somehow has a different dataSource than the simpleJdbcTemplate. Not sure how this would be, though, since there's only one dataSource defined in the DaoTests-context.xml file.
Hibernate requires all foreign key relations to be present in order to select out the Gear object. There are a couple of joins that are not present since I'm hardcoding those in fld2/fld3/fld4.
The DAO won't act on the uncommitted data. But why would the simpleJdbcTemplate honor this? I'd assume they both do the same thing.
Underpants gnomes. But where's the profit?
What a difference a couple hours of sleep makes. I woke up and thought "I should check the logs to see what query is actually being executed." And of course it turns out that hibernate was configured to generate some inner joins for a few of the foreign keys. Once I supplied those dependencies it worked like a charm.
I'm loving the automatic rollback on every test concept. Integration tests, here I come!