Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Worthwhile to add in Quickstart? #230

Closed
sethdorris opened this issue Dec 23, 2015 · 19 comments
Closed

Worthwhile to add in Quickstart? #230

sethdorris opened this issue Dec 23, 2015 · 19 comments

Comments

@sethdorris
Copy link

Suggestion for Adding to QuickStart Guide

A Beginners Guide to Mocking and why

Proposed Table of Contents

1. Use Cases

A. Context Mocking
B. Repo Mocking
C. DBSets Mocking

2. Setting up your Mocks

A. Mock Context
B. Mock Repo
C. Mock Sets

3. Test Setup and Cleanup

-Why and how

...etc

Would implementing a beginners guide to mocking be something that should be done, as I found it difficult to know where to begin for mocking and what I needed to mock when I first started mocking.

The moq docs are good, but I think geared more towards users with mocking experience?

If this would be something perceived as value added, it is something that I could work on..?

@kzu
Copy link
Contributor

kzu commented Dec 23, 2015

👍 sounds good. Should that be part of the current quickstart wiki or a
new page?

On Wed, Dec 23, 2015 at 11:27 AM Seth Dorris notifications@github.com
wrote:

Suggestion for Adding to QuickStart Guide A Beginners Guide to Mocking
and why

Proposed Table of Contents

  1. Use Cases

A. Context Mocking
Why?
How? (Steps)
B. Repo Mocking
Why repo pattern?
Why mock this?
How?
C. DBSets Mocking

...etc

Would implementing a beginners guide to mocking be something that should
be done, as I found it difficult to know where to begin for mocking and
what I needed to mock when I first started mocking.

The moq docs are good, but I think geared more towards users with mocking
experience?

If this would be something perceived as value added, it is something that
I could work on..?


Reply to this email directly or view it on GitHub
#230.

@TJSoftware
Copy link

@sethdorris I agree, coming into mocking for the first time has not been easy for me either. I am even familiar with lambda expressions, etc, so it is more the concept of what a mock is, can/cannot do, and how it works. If I did not have someone in the office to help I would have had a great deal more trouble.

@kzu Good timing ;). IMHO it could be a part of quickstart.

@TJSoftware
Copy link

@kzu I thought a bit more about it and I came up with a sample layout. If this is not a valid use of Moq please correct me. The //??? comments are in need of a description on what happens/why this line is needed. The part that I was most confused with is understanding what I was testing. I think that naming the example with ClassToTest might help with that.

using Moq;
using Xunit;

namespace MoqTesting.MyTests {
  public class Example {
    [Fact]
    public void ExampleTest() {
      //???
      var mockDependency = new Mock<ITestDependency>();

      //???
      mockDependency.Setup(md => md.DependencyMethod()).Returns("SUCCESS");

      //???
      var mockResult = ClassToTest.MethodToTest(mockDependency.Object);

      //???
      Assert.Equal("SUCCESS", mockResult);

      //???
      mockDependency.VerifyAll();
    }

    public interface ITestDependency {
      string DependencyMethod();
    }

    public class TestDependency : ITestDependency {
      public string DependencyMethod() {
        return "dependency value";
      }
    }

    public class ClassToTest {
      public static string MethodToTest(ITestDependency dependency) {
        return dependency.DependencyMethod();
      }
    }
  }
}

@sethdorris
Copy link
Author

So This is kind of where I am heading...

Before I get deeper, anyone have any suggestions? Would you prefer I just finish it and we can make adjustments as necessary (especially to styling :P)

The beginner's guide to Mocking (using Moq)

Obivously there is always more than one solution for writing unit tests / mocking.

In this guide I will show you how to Mock using a test class with properties that contain the Classes I want to mock and my Repository.

This guide will show you how to write Setup and Teardown helper methods for your Test Class.. but more on that later.

Table of Contents

Assumptions
Why Mock
Explore Full Example
1. Create Test Class
2. Create Setup Helper Method

Assumptions

In order to really understand what is happening, you probably should be familiar with the following concepts:

Why does one need to Mock?

Mocking is used when you need to test your application's interaction with the database. This will ensure that your test methods do not inject data into your database when the test methods are run.

Explore Full Example

** Let's explore the following code as a whole and then we can break it down bit by bit **

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using My.Models;
using System.Data.Entity;
using Moq;
using System.Collections.Generic;
using System.Linq;

namespace My.Tests.Models
{
    [TestClass]
    public class RepositoryTests
    {
        private Mock<MyContext> _context;
        private MyRepository _repo;
        private Mock<DbSet<MySet>> _mySet;

        private void ConnectMocksToDataStore(IEnumerable<MySet> data_store)
        {
            var data_source = data_store.AsQueryable();
            _mySet.As<IQueryable<MySet>>().Setup(data => data.Provider).Returns(data_source.Provider);
            _mySet.As<IQueryable<MySet>>().Setup(data => data.Expression).Returns(data_source.Expression);
            _mySet.As<IQueryable<MySet>>().Setup(data => data.ElementType).Returns(data_source.ElementType);
            _mySet.As<IQueryable<MySet>>().Setup(data => data.GetEnumerator()).Returns(data_source.GetEnumerator());
            _context.Setup(a => a.SetName).Returns(_mySet.Object);
        }

        [TestInitialize]
        public void Initialize()
        {
            _context = new Mock<MyContext>();
            _mySet = new Mock<DbSet<MySet>>();
            _repo = new MyRepository(_context.Object);
        }

        [TestCleanup]
        public void Cleanup()
        {
            _context = null;
            _mySet = null;
            _repo = null;
        }

        [TestMethod]
        public void RepositoryTestsEnsureICanGetAllGamers()
        {
            List<User> users = new List<User>()
            {
                new User {UserID = 1, Handle = "Stiffy"},
                new User {UserID = 2, Handle = "Michael"}
            };

            _mySet.Object.AddRange(users);
            ConnectMocksToDataStore(users);

            var actual = _repo.GetAllUsers();  
            Assert.AreEqual(1, actual[0].UserID);
            CollectionAssert.AreEqual(users, actual);
        }
     }
}

Step One

Create Test Class with Private Data Members Containing Your Mocks and Repo.

Let's take a look at the first part of the code you saw earlier:

    [TestClass]
    public class RepositoryTests
    {
        private Mock<MyContext> _context;
        private MyRepository _repo;
        private Mock<DbSet<MySet>> _mySet;

  1. I've created a class with private properties that WILL contain:
  2. a Mock of my DbContext
  3. a Mock of my DbSet(s)
  4. my Repository

In the line of code
private Mock<MyContext> _context;
you can see I've created a private data member named _context of type Mock<MyContext> where MyContext is the name of my DbContext class I have already created.

As a reminder, I have not Mocked anything at this point. I've merely created private data members that will hold my Mocks.

Second Step

Create Setup Helper Method

Let's take a look at this bit of code:

        [TestInitialize]
        public void Initialize()
        {
            _context = new Mock<MyContext>();
            _mySet = new Mock<DbSet<MySet>>();
            _repo = new MyRepository(_context.Object);
        }

What this does:

the [TestInitialize] Attribute Tag Identifies the method to run before the test to allocate and configure resources needed by all tests in the test class.

This seems simple enough right? I am still setting up my environment so that I can actually write my tests. I've now mocked my DbContext class MyContext, my DbSet MySet, and I've created an instance of my repository named MyRepository and passed in my mocked Context _context.

So why did you pass in _context.Object and not simply _context when calling the MyRepository Constructor ?

This is because I have MOCKED my context.

MOQ API reads - Object(Property) - Gets the Mocked Object Instance

In other words using .Object actually EXPOSES the context (in this case the DbContext class I've made called MyContext) and is allowing me to use it as if it was not Mocked.

@TJSoftware
Copy link

@sethdorris Sorry for the slow response, holiday break ;). I started going through your example.

  1. I think your formatting looks nice, just adjustments for webpage vs post ;).
  2. I like the external references, they will be helpful to new users.
  3. Where new users may get lost is the references you have that you do not show in the example, for example MyContext and MySet will need some prior knowledge to create. The example can have this later on.
  4. I am using DNX (.Net 5 library) and I think that changes the attributes. Only having used XUnit and a few others like that I am not sure if this is a change or not. I am unable to find a package for Microsoft.VisualStudio.TestTools.UnitTesting on NuGet or on a reverse package search. The dependencies that I am using are in screenshot 1, I see several build errors, see screenshot 2.
  5. I think this is a great tutorial, perhaps the step after a Hello World tutorial. Unit Testing can be used for more than just database testing, I agree that it is a primary use and that the purpose is to prevent modification of the dependency. Your dependency may be a flat file, an office file, or any other resource that you wish to mock.
Screenshot 1

image

Screenshot 2

image

@kzu
Copy link
Contributor

kzu commented Dec 28, 2015

The build errors are due to the usage of MSTest. I'd switch to xunit, since
that's what Moq source itself uses.

Also, what do you guys think about making this part of the Wiki? Or maybe
even the moq.github.io Github pages instead?

On Mon, Dec 28, 2015 at 1:18 PM TJSoftware notifications@github.com wrote:

@sethdorris https://github.com/sethdorris Sorry for the slow response,
holiday break ;). I started going through your example.

  1. I think your formatting looks nice
  2. I like the external references, they will be helpful to new users.
  3. Where new users may get lost is the references you have that you do
    not show in the example, for example MyContext and MySet will need
    some prior knowledge to create. The example can have this later on.
  4. I am using DNX (.Net 5 library) and I think that changes the
    attributes. Only having used XUnit and a few others like that I am not sure
    if this is a change or not. I am unable to find a package for
    Microsoft.VisualStudio.TestTools.UnitTesting
    https://www.nuget.org/packages?q=Microsoft.VisualStudio.TestTools.UnitTesting
    on NuGet. The dependencies that I am using are in screenshot 1, I see
    several build errors, see screenshot 2.
  5. I think this is a great tutorial, perhaps the step after a Hello
    World tutorial. Unit Testing can be used for more than just database
    testing, I agree that it is a primary use and that the purpose is to
    prevent modification of the dependency. Your dependency may be a flat file,
    an office file, or any other resource that you wish to mock.

Screenshot 1

[image: image]
https://cloud.githubusercontent.com/assets/4823412/12021210/8728eb52-ad41-11e5-9aff-0012ffadaa27.png
Screenshot 2

[image: image]
https://cloud.githubusercontent.com/assets/4823412/12021130/a240561a-ad40-11e5-9ed8-22ba3430ac73.png


Reply to this email directly or view it on GitHub
#230 (comment).

@TJSoftware
Copy link

@kzu I think that this needs to be on the Wiki, it does not need to be part of the quick start necessarily, perhaps a new wiki page, but part of the quick start makes sense as well. When I took a look at moq.github.io I did not see any areas with tutorials, just a twitter feed and a couple of old articles. I like the idea of more resources, however I am currently not maintaining the code so I tend to say only code in one place. I will defer to you on moq.github.io.

image

@kzu
Copy link
Contributor

kzu commented Dec 28, 2015

Yeah, the website is basically moqthis.com, provided by github pages
through the repo https://github.com/Moq/moq.github.io

The goal was to have a nice homepage there, like http://autofac.org/, which
comes from https://github.com/autofac/autofac.github.com (.io is the new
repo extension name to use, but they did it quite some time ago).

I'm all for getting 99.99% inspiration from Autofac, and I'm sure Nick will
be Ok with that. he's a good friend :)

On Mon, Dec 28, 2015 at 2:07 PM TJSoftware notifications@github.com wrote:

@kzu https://github.com/kzu I think that this needs to be on the Wiki,
it does not need to be part of the quick start necessarily, perhaps a new
wiki page, but part of the quick start makes sense as well. When I tool a
look at moq.github.io I did not see any areas with tutorials, just a
twitter feed and a couple of old articles. I like the idea of more
resources, however I am currently not maintaining the code so I tend to say
only code in one place. I will defer to you on moq.github.io.

[image: image]
https://cloud.githubusercontent.com/assets/4823412/12022168/87964fd6-ad4a-11e5-82c6-84fb6de759ac.png


Reply to this email directly or view it on GitHub
#230 (comment).

@sethdorris
Copy link
Author

So do you guys want me to edit my guide to use XUnit then? What additional changes do you want to see in the write up itself? I do appreciate the feedback gentlemen.

@TJSoftware
Copy link

@sethdorris Outside of placing all classes (MyContext, etc) in the example (and the conversion to xUnit) I do not see anything else that needs to be done. This is a great real world example.

@kzu
Copy link
Contributor

kzu commented Dec 28, 2015

👍

On Mon, Dec 28, 2015 at 2:56 PM TJSoftware notifications@github.com wrote:

@sethdorris https://github.com/sethdorris Outside of placing all
classes (MyContext, etc) in the example (and the conversion to xUnit) I
do not see anything else that needs to be done. This is a great real world
example.


Reply to this email directly or view it on GitHub
#230 (comment).

@sethdorris
Copy link
Author

Thanks gents. I will work on those changes.. would you prefer to see a draft of the completed write up in here ?

@kzu
Copy link
Contributor

kzu commented Dec 28, 2015

Sure thing. Maybe a proper PR would make it easier to comment on specific
parts, and once it's done we can see where to place it?

On Mon, Dec 28, 2015 at 3:09 PM Seth Dorris notifications@github.com
wrote:

Thanks gents. I will work on those changes.. would you prefer to see a
draft of the completed write up in here ?


Reply to this email directly or view it on GitHub
#230 (comment).

@TJSoftware
Copy link

@kzu Seth started a PR here with the old example #232

@sethdorris
Copy link
Author

I hope to have the edits made and up by Saturday night.

@sethdorris
Copy link
Author

Sorry it's been a while since I have updated this however, I was looking at moving to using xunit for this, and the reason why I chose to stick with MS unit test was due to its [TestInitialize] tag.. @TJSoftware I do not get build errors when using MS unit test with MOQ... I would LIKE to keep using MS Unit test, as I BELIEVE replicating the TestInitialize feature in xUnit is a lot more work.... can we stick with using MS Unit Test?

@TJSoftware
Copy link

NP, I know how busy life gets.

I would LIKE to keep using MS Unit test, as I BELIEVE replicating the TestInitialize feature in xUnit is a lot more work.... can we stick with using MS Unit Test?

You can use whatever unit testing you like, however, please keep in mind this comment from kzu.

The build errors are due to the usage of MSTest. I'd switch to xunit, since
that's what Moq source itself uses.

That is why it is helpful for others to work with xUnit as Moq will work with xUnit. I have been focused on some other learning for the time being. I will try to improve on my simple example by adding some comments on my understanding of how this works. Perhaps we can start with a simple generic example first then build up to a real world example. I do not expect to have any work on this till the weekend (or later).

@sethdorris
Copy link
Author

@TJSoftware I haven't experienced any issue with MS Test with Moq.. Totally understand, this guide, as we both are well aware, is not something that is pressing.. and I can only get around to it every now since my free time is limited.

@stakx
Copy link
Contributor

stakx commented Sep 27, 2017

@sethdorris, @TJSoftware - how shall we go on with this? You may have seen that I closed the PR, mostly because I feel such content should go to the wiki and not into the readme... and it's also been dormant for a long time.

I would suggest that if you want to continue working on this, start a new wiki section titled "User contributions" or similar, then put your article as a page under it. As the wiki is collaboratively edited, the content doesn't have to be perfect right from the start, I'd reserve discussions here for major debatable points.

If you do continue with this, I'd like to add a couple of points for your consideration:

  • I'd also vote for xUnit.NET, not MSTest. AFAIK [TestInitialize] is easy to replace, just move the stuff over to the constructor (see https://xunit.github.io/docs/comparisons.html).

  • For a beginner's tutorial, mocking DB accesses is a rather cruel topic IMHO. DB code is probably among the hardest things to test. Also, since the article was first proposed, EF Core came out with an in-memory context for testing purposes -- perhaps the article could be updated to take that into account, it might make some things a lot simpler.

I am closing this issue for now, assuming that you guys are busy elsewhere. If you want to resume work on this, feel free to start editing in the wiki, and if there's need for discussion, I'm happy to reopen this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants