I'm working on an application right now which uses some mock classes which were "hand written" instead of using a mock framework. I haven't had much experience with using mock frameworks, but I've wanted to learn more about them. There are many mock frameworks out there, I chose to use moq because the test cases for ASP.NET MVC use moq. What I wanted to do was replace the mock class that I created with a moq class. If you have ever created mock classes before then you probably know that they are pretty annoying to maintain. What I mean is that if you add a method/property to the interface which the mock class implements then you have to update the mock just to get it to build. This is annoying and kinda makes people not to use the mock which then ends up in ignoring/commenting out test cases. To avoid all of this most mock frameworks, including moq, just require you to specify behavior for methods/properties which you are ready to exercise in your test cases. Now I’d like to show you the mock class that I had. This interface that it is mocking is used to abstract the data store.

001internal class MockModelContext :IModelContext
002{
003    public User CreateUser(User user)
004    {
005        // if id is not set, set it and just return it
006        if (user.Id <= 0)
007        {
008            user.Id = 1;
009        }
010 
011        return user;
012    }
013 
014    public User GetUserByEmail(string email)
015    {
016        if (string.IsNullOrEmpty(email)) { throw new ArgumentNullException("email"); }
017 
018        User user = CreateDummyUser();
019        user.Email = email;
020 
021        return user;
022    }
023 
024    public User GetUser(Expression<func<user, bool="">> filter)
025    {
026        return CreateDummyUser();
027    }
028 
029    public IList<task> GetRecentTasks()
030    {
031        IList<task> tasks = new List<task>()
032        {
033            new Task()
034            {
035                CreatedDate = new DateTime(2010,1,1,1,1,1),
036                CreatorId = 1,
037                //Description ="Description 01 here",
038                Headline="Headline 01 here",
039                Id = 1,
040                LastEditedDate= new DateTime(2010,1,1,1,1,1),
041                LastEditOwnerId=1,
042                Name = "Name here",
043                NumViews = 3,
044                Script = @"<scripthere>script</scripthere>",
045                // TODO: Tags
046                // TODO: TaskComments
047                User = new User()
048                {
049                    Email ="one@hotmail.com",
050                    FirstName="First",
051                    Id=2,
052                    LastName="Last",
053                    MiddleName="Middle",
054                }
055            },
056            new Task()
057            {
058                CreatedDate = new DateTime(2010,1,1,1,1,1),
059                CreatorId = 1,
060                //Description ="Description 02 here",
061                Headline="Headline 02 here",
062                Id = 1,
063                LastEditedDate= new DateTime(2010,1,1,1,1,1),
064                LastEditOwnerId=1,
065                Name = "Name here",
066                NumViews = 3,
067                Script = @"<scripthere>script2</scripthere>",
068                // TODO: Tags
069                // TODO: TaskComments
070                User = new User()
071                {
072                    Email ="one@hotmail.com",
073                    FirstName="First",
074                    Id=2,
075                    LastName="Last",
076                    MiddleName="Middle",
077                }
078            }
079        };
080 
081        return tasks;
082    }
083    protected internal User CreateDummyUser()
084    {
085        User user = new User()
086        {
087            Email = "email",
088            FirstName = "First",
089            LastName = "Last",
090            MiddleName = "Middle"
091        };
092 
093        return user;
094    }
095    public User GetUserByOpenIdUrl(string openIdUrl)
096    {
097        throw new NotImplementedException();
098    }
099    public IList<task> GetRecentTasks(IEnumerable<string> includeList)
100    {
101        throw new NotImplementedException();
102    }
103    public Task AddTask(Task task)
104    {
105        throw new NotImplementedException();
106    }
107    public User GetUserById(long id)
108    {
109        User user = this.CreateDummyUser();
110        user.Id = id;
111 
112        return user;
113    }
114    public User SaveUser(User user)
115    {
116        throw new NotImplementedException();
117    }
118    public Task GetTaskById(long id)
119    {
120        throw new NotImplementedException();
121    }
122}</string></task></task></task></task></func<user,>

Take notice of the methods which just throw a NotImplementedException, these are methods that I just added to the interface and haven’t yet written test cases for. (Yeah I know I’m not following true TDD, but I never claimed to be either). Now you can compare that to these methods which use moq to create the mock.

001private Mock<imodelcontext> CreateMockModelContext()
002{
003    var context = new Mock<imodelcontext>();
004 
005    context.Setup(c => c.CreateUser(It.IsAny<user>()))
006        .Returns<user>(user =>
007        {
008            if (user.Id <= 0)
009            {
010                user.Id = 1;
011            }
012            return user;
013        });
014 
015    context.Setup(c => c.GetUserByEmail(It.IsAny<string>()))
016        .Returns<string>(email =>
017            {
018                if (email == null) { throw new ArgumentNullException("email"); }
019 
020                User user = this.CreateDummyUser();
021                user.Email = email;
022 
023                return user;
024            }); ;
025 
026    context.Setup(c => c.GetUserById(It.IsAny<long>()))
027        .Returns<long>(id =>
028        {
029            User user = new User();
030            user.Id = id;
031            return user;
032        });
033 
034    context.Setup(c => c.GetRecentTasks())
035        .Returns(() =>
036        {
037            IList<task> tasks = new List<task>()
038            {
039                new Task()
040                {
041                    CreatedDate = new DateTime(2010,1,1,1,1,1),
042                    CreatorId = 1,
043                    //Description ="Description 01 here",
044                    Headline="Headline 01 here",
045                    Id = 1,
046                    LastEditedDate= new DateTime(2010,1,1,1,1,1),
047                    LastEditOwnerId=1,
048                    Name = "Name here",
049                    NumViews = 3,
050                    Script = @"<scripthere>script</scripthere>",
051                    // TODO: Tags
052                    // TODO: TaskComments
053                    User = new User()
054                    {
055                        Email ="one@hotmail.com",
056                        FirstName="First",
057                        Id=2,
058                        LastName="Last",
059                        MiddleName="Middle",
060                    }
061                },
062                new Task()
063                {
064                    CreatedDate = new DateTime(2010,1,1,1,1,1),
065                    CreatorId = 1,
066                    //Description ="Description 02 here",
067                    Headline="Headline 02 here",
068                    Id = 1,
069                    LastEditedDate= new DateTime(2010,1,1,1,1,1),
070                    LastEditOwnerId=1,
071                    Name = "Name here",
072                    NumViews = 3,
073                    Script = @"<scripthere>script2</scripthere>",
074                    // TODO: Tags
075                    // TODO: TaskComments
076                    User = new User()
077                    {
078                        Email ="one@hotmail.com",
079                        FirstName="First",
080                        Id=2,
081                        LastName="Last",
082                        MiddleName="Middle",
083                    }
084                }
085 
086            };
087            return tasks;
088        });
089 
090    return context;
091}
092protected internal User CreateDummyUser()
093{
094    User user = new User()
095    {
096        Email = "email",
097        FirstName = "First",
098        LastName = "Last",
099        MiddleName = "Middle"
100    };
101 
102    return user;
103}</task></task></long></long></string></string></user></user></imodelcontext></imodelcontext>

Since I’m just mocking methods all I’m really doing here is using the moq Setup method (formerly known as Expect), and the Returns method to implement the behavior that I needed. The key to note here is that if you need to access the parameter(s) passed into the method, then you will have to used Returns and pass in a lambda expression that contains the behavior. In that lamdba you can name the parameter anything you want, but I would suggest you name it the same name that the method you are mocking names it. This makes it much more understandable what you are actually doing.

Sayed Ibrahim Hashimi


Comment Section

Comments are closed.