Unit testing FetchEntityCollection

Posts   
 
    
Posts: 116
Joined: 18-Feb-2006
# Posted on: 07-Jul-2009 17:01:09   

I was curious to find out how people are testing their retrieval queries. There are 2 approaches I would think to take:

  1. verifying the SQL where statement that gets generated from the adapter
  2. use an in memory set and verify the returned resultset

Regardless, here is the what I would like to test:

I have a standard users table: UserName, FirstName, LastName. In my application, I have a search page, where I can enter keywords to search these 3 fields.

Here is what the code might look like:

    public class UserSearchService : IDisposable
    {
        private IDataAccessAdapter _adapter;
        /// <summary>
        /// Initializes a new instance of the UserSearchService class.
        /// </summary>
        /// <param name="adapter"></param>
        public UserSearchService(IDataAccessAdapter adapter)
        {
            _adapter = adapter;
        }

        private IEnumerable<UserEntity> SearchUsers(string keywords)
        {
            keywords = String.Format("%{0}%", keywords);
            IPredicate filter = new PredicateExpression(UserFields.UserName % keywords);
            filter.AddWithOr(UserFields.FirstName % keywords);
            filter.AddWithOr(UserFields.LastName % keywords);

            EntityColllection<UserEntity> users = new EntityCollection<UserEntity>();
            IRelationPredicateBucket bucket = new RelationPredicateBucket(filter);
            _adapter.FetchEntityCollection(users, bucket, 0, null, null, null, 0, 0);
            return users;           
        }
        
        public void  Dispose()
        {
            if (_adapter != null)
                _adapter.Dispose();
        }

    }

How would I be able to test this code **WITHOUT **using the database? I don't want to pass in a concrete DataAccessAdapter object to the class.

So if I passed a keyword of "Joe", I want to test each field returns properly if "Joe" is in the field.

MTrinder
User
Posts: 1461
Joined: 08-Oct-2008
# Posted on: 07-Jul-2009 20:56:51   

The standard method in this case is to use one of the many Mock Object frameworks. These let you dynamically create an instance of an object which implements IDataAccessAdater. You then tell it what calls to expect and what results to return.

The trouble with that in this case is that you are then not really testing anything in the code sample you have given.

The other way to test code such as your sample is to have a test database with known data in it,and to use an actual DataAccessAdapter to check that the results you are getting are what you expect.

Matt

Posts: 116
Joined: 18-Feb-2006
# Posted on: 07-Jul-2009 21:25:46   

I would be able to mock the IDataAccessAdapter (using Typemock), but you are correct in that I would just be mocking what it's returning anyway, which doesn't actually test this method.

I don't want to use a live database as these are unit tests, not integration tests.

I don't see a way that this could be refactored to be able to test the resultset. Any other suggestions?

arschr
User
Posts: 894
Joined: 14-Dec-2003
# Posted on: 07-Jul-2009 21:55:43   

In theory you should be unit testing not the fetch collection, but your building of the predicate expression and the other parameters to the fetch collection.

So you would break this into 2 procedures one building an object that would hold the predicate expression, prefetch paths, and other parameters that the fetch will use and a second that takes that object and uses it's properties to feed the fetch.

You would unit test the first by asserting that the properties on the object were correct (that the predicate expression was what you expected for example. You would probably not unit test the second or if you did you would asset that something was returned.

Posts: 116
Joined: 18-Feb-2006
# Posted on: 07-Jul-2009 22:00:56   

So breaking out the predicate into it's own method, how would I check the SQL it would generate?

What would the test condition be?

arschr
User
Posts: 894
Joined: 14-Dec-2003
# Posted on: 07-Jul-2009 23:53:46   

So breaking out the predicate into it's own method, how would I check the SQL it would generate?

What would the test condition be?

The SQL is generated by a 3rd party component, so you wouldn't unit test it, since you have no control over their code. If anything you would integration test it.

You would unit test your code (methods and objects) without external dependencies. So you might unit test (assert) that the predicate expression you built had 1 predicate, had a equals predicate, had a value of a certain value, based on the test values passed to the predicate generating method.

Roy Osherove (author of "The Art of Unit Testing") has a good discussion about this on the latest Hanselminutes podcast.

Posts: 116
Joined: 18-Feb-2006
# Posted on: 08-Jul-2009 17:44:21   

arschr wrote:

You would unit test your code (methods and objects) without external dependencies. So you might unit test (assert) that the predicate expression you built had 1 predicate, had a equals predicate, had a value of a certain value, based on the test values passed to the predicate generating method.

So if my code was refactored to this:

    public class UserSearchService : IDisposable
    {
        private IDataAccessAdapter _adapter;
        /// <summary>
        /// Initializes a new instance of the UserSearchService class.
        /// </summary>
        /// <param name="adapter"></param>
        public UserSearchService(IDataAccessAdapter adapter)
        {
            _adapter = adapter;
        }
        
        public IEnumerable<UserEntity> GetUserCollection(IPredicateExpression filter)
        {
            EntityCollection<UserEntity> users = new EntityCollection<UserEntity>();
            IRelationPredicateBucket bucket = new RelationPredicateBucket(filter);
            _adapter.FetchEntityCollection(users, bucket, 0, null, null, null, 0, 0);
            return users;           
        }
        
        public IPredicate BuildSearchPredicate(keywords)
        {
            keywords = String.Format("%{0}%", keywords);
            IPredicate filter = new PredicateExpression(UserFields.UserName % keywords);
            filter.AddWithOr(UserFields.FirstName % keywords);
            filter.AddWithOr(UserFields.LastName % keywords);
            return filter;
        }
        
        public void Dispose()
        {
            if (_adapter != null)
                _adapter.Dispose();
        }

    }

I can unit test BuildSearchPredicate to make sure the IPredicateExpression has 3 filters and the keywords gets build property, but that doesn't allow me to test GetUserCollection.

Is there no way to test GetUserCollection as a unit test vs integration test?

Story I would like to test:

UserStory wrote:

If I search for the keyword, "Joe", the form will return users that have joe in the Username, FirstName and LastName fields.

Is this an integration test because of the dependency on the database?

Roy Osherove (author of "The Art of Unit Testing") has a good discussion about this on the latest Hanselminutes podcast.

I listened to the podcast too smile

arschr
User
Posts: 894
Joined: 14-Dec-2003
# Posted on: 08-Jul-2009 17:59:45   

Is there no way to test GetUserCollection as a unit test vs integration test?

Story I would like to test:

UserStory wrote: If I search for the keyword, "Joe", the form will return users that have joe in the Username, FirstName and LastName fields.

depends on your definition of unit test. To me is seems that the unit test would be "When the user searches for Joe does my code build the proper predicate, one that looks for Joe in the any of UserName, FirstName, or LastName columns.

Once you bring the database into it and look at the results you are testing not only your code but the LlblGen Code, the SQL Server Code and the contents on the database, To me this is integration testing.

Is this an integration test because of the dependency on the database?

Yes and because of the dependency of the results of the Sql query.

Posts: 116
Joined: 18-Feb-2006
# Posted on: 08-Jul-2009 18:18:29   

Is there a way to test predicates on in-memory objects?

So an example:

  1. Set up an EntityCollection with some fake users
  2. Apply the predicate to it
  3. Assert the entity that should be returned after the predicate has been applied
arschr
User
Posts: 894
Joined: 14-Dec-2003
# Posted on: 08-Jul-2009 21:51:40   

Is there a way to test predicates on in-memory objects?

Yes, but remember there is not a 1 to 1 correspondence between database predicates and memory predicates.

Posts: 116
Joined: 18-Feb-2006
# Posted on: 08-Jul-2009 22:32:47   

Here is what I did to test this trivial example:

I extracted out the predicate creation into a static method, then applied it to an in-memory filter.

    public class UserSearchService : IDisposable
    {
        private IDataAccessAdapter _adapter;
        /// <summary>
        /// Initializes a new instance of the UserSearchService class.
        /// </summary>
        /// <param name="adapter"></param>
        public UserSearchService(IDataAccessAdapter adapter)
        {
            _adapter = adapter;
        }

        public IEnumerable<UserEntity> GetUserCollection(string keywords)
        {           
            EntityColllection<UserEntity> users = new EntityCollection<UserEntity>();
            IRelationPredicateBucket bucket = new RelationPredicateBucket(GetSearchFilter(keywords));
            _adapter.FetchEntityCollection(users, bucket, 0, null, null, null, null, null);
            return users;           
        }

        public static IPredicate GetSearchFilter(string keywords)
        {
            keywords = String.Format("%{0}%", keywords);
            IPredicate filter = new PredicateExpression(UserFields.UserName % keywords);
            filter.AddWithOr(UserFields.FirstName % keywords);
            filter.AddWithOr(UserFields.LastName % keywords);
            return filter;
        }
        public void Dispose()
        {
            if (_adapter != null)
                _adapter.Dispose();
        }

    }

    [TestFixture]
    public class UserSearchServiceTests
    {
        private EntityCollection<UserEntity> users;

        [TestFixtureSetUp]
        public void InitializeAllTests()
        {
            users = new EntityCollection<UserEntity>();
            users.Add(new UserEntity {Username = "frizzo", FirstName = "Frank", LastName = "Rizzo"});
            users.Add(new UserEntity {Username = "jbrown", FirstName = "Jessie", LastName = "Brown" });
            users.Add(new UserEntity {Username = "kbrubek", FirstName = "Kent", LastName = "Brubek" });
        }

        [TestFixtureTearDown]
        public void CleanupAllTests()
        {
            if (users != null)
                users.Dispose();
        }

        [Test]
        public void SearchFilter_ReturnsUsernameFilter_Success()
        {
            IPredicateExpression filter = UserSearchService.GetSearchFilter("brown");
            IEntityView2 filteredUsers = new EntityView2<UserEntity>(users, filter);
            Assert.AreEqual(1, filteredUsers.Count);
        }
                
        [Test]
        public void SearchFilter_MulitpleFilterOnUsernameFilter_Success()
        {           
            IPredicateExpression filter = UserSearchService.GetSearchFilter("b");
            IEntityView2 filteredUsers = new EntityView2<UserEntity>(users, filter);
            Assert.AreEqual(2, filteredUsers.Count);
        }
    }   

I realize that if there are multiple entity filters, this doesn't work, but at least testing just the single entity fields does here.

Thanks everyone for helping towards a solution to this.

~Steve