Best practices for using Mocks in TDD (MOQ) - c#

I am new to using Mocks. But what are it's main purposes? I'm going to start by using Moq to test my application (and NUnit).
For example, I have code that does things like this:
My webpage code behind:
public partial class MyWebpage
{
protected string GetTitle(string myVar)
{
return dataLayer.GetTitle(myVar);
}
}
My data access layer:
public class DataLayer
{
public string GetTitle(string myVar)
{
// Create the query we want
string query = "SELECT title FROM MyTable " +
"WHERE var = #myVar";
//ENTER PARAMETERS IN HERE
// Now return the result to the view
return this.dataProvider.ExecuteMySelectQuery(
dr =>
{
//DELEGATE DATA READER PASSED IN AND TITLE GETS RETURNED
},
query,
parameters);
}
}
My data provider talks and interacts directly with the db:
public class DataProvider
{
public T ExecuteMySelectQuery<T>(Func<IDataReader, T> getMyResult, string selectQuery, Dictionary parameters)
{
//RUNS AND RETURNS THE QUERY
}
}
What's the best way to test all of this?

If you want to test the layers separately, you would need to create interfaces for your DataProvider and DataLayer classes that expose the methods that you want to Mock. Then you can use a mocking framework - NSubstitute is very good, less code to write to create the mocks - to mock out the calls to the dependent classes, leaving you to test the code within that specific unit
public interface IDataProvider
{
T ExecuteMySelectQuery<T>(Func<IDataReader, T> getMyResult, string selectQuery, Dictionary parameters);
}
public interface IDataLayer
{
string GetTitle(string myVar);
}
public class DataLayer
{
private IDataProvider dataProvider;
public DataLayer(IDataProvider dataProvider)
{
this.dataProvider = dataProvider;
}
}
Then, in your test code, you create mocks instead of real objects and pass those into the constructor when you instantiate your test objects. To test the DataLayer:
[Test]
public void WhenRetievingTitleFromDataStore_ThenDataLayerReturnsTitle()
{
var title = "Title";
var dataProviderMock = new Mock<IDataProvider>(MockBehavior.Strict);
dataProviderMock.Setup(x => x.ExecuteMySelectQuery(<parameters>)).Returns(title);
var dataLayer = new DataLayer(dataProviderMock.Object);
Assert.That(dataLayer.GetTitle(It.IsAny<string>(), Is.EqualTo(title));
}

The only thing that can go wrong with that is the DB call (the query or the returned result is of wrong data types). That can't be mocked. You need to do integration tests and not unit tests.
Typically you only mock to be able to test logic in the code. You should for instance test so that the data mapper (this.dataProvider.ExecuteMySelectQuery) works as defined. but that's of the scope of the code in question.
Update
So you got the following classes:
public class DataLayer
{
public string GetTitle(string myVar)
{
// Create the query we want
string query = "SELECT title FROM MyTable " +
"WHERE var = #myVar";
//ENTER PARAMETERS IN HERE
// Now return the result to the view
return this.dataProvider.ExecuteMySelectQuery(
dr =>
{
//DELEGATE DATA READER PASSED IN AND TITLE GETS RETURNED
},
query,
parameters);
}
}
public class DataProvider
{
public T ExecuteMySelectQuery<T>(Func<IDataReader, T> getMyResult, string selectQuery, Dictionary parameters)
{
//RUNS AND RETURNS THE QUERY
}
}
If we examine the ExecuteMySelectQuery we can see that the DataLayer class is dependent of how the types that the database returns since the DataProvider just ease the query execution. One could say that it's an addon on top of ADO.NET.
That also means that you can never guarantee that DataLayer return what's promised without involving the database. Let's for instance assume that the table in the database has a column called title but someone managed to use the int data type instead.
The things that can go wrong are
The query is incorrect
The schema in the database is incorrect (wrong column names, data types etc)
The mapping
None of those errors can be detected nor tested with the help of a mock.
If you on the other hand use the DataLayer clas in another class you can of course mock it. Because the DataLayer class itself is a complete abstraction. That means that the callers of the class doesn't have to be aware of anything beneath it. Hence mocking is perfectly fine.

Related

Mocking a method to assign value to field in Model C# Moq

I need to add a method to a model that given some parameters assigns a value to one of the model's fields.
public class ModelName: SomeModel<ModelName>, IModelName
{
[Field]
public string SomeField{ get; set; }
[Field]
public string FieldSetByMethod{ get; set; }
public new async Task MethodToSetField(string parameter)
{
var someClassInstance = new SomeExternalClass(parameter);
FieldSetByMethod = someClassInstance(parameter).method();
}
}
Now when I'm writing unit tests and I want to have a way of checking that this MethodToSetField was called. However, I can't really actually call the MethodToSetField method as creating SomeExternalClass is not desirable (e.g. because it creates unique ID).
I don't really have experience with neither C# nor Moq. How can I mock this function so it behaves more or less like this:
ModelNameInstance.Setup(c => c.MethodToSetField("Parameter")).Assigns(FieldSetByMethod,"DummyValue");
Or maybe I can somehow restructure the code / write tests in a way to imitate this behavior?
You could inject ISomeExternalClass into this class and then mock it, and test against the mock, or if you can't do that - inject ISomeExternalClassFactory into this class and then mock it. ISomeExternalClassFactory mock would return a mock of ISomeExternalClass that you could setup and test against.

Can I generate a code from an instance in the memory to re-create it later?

Imagine I have an instance with its properties set (which is for instance loaded from the db),
and from this instance in the memory, I want to obtain a code with all the public properties set upon the current values, so that I can use this in my unit tests to re-create the instance.
Is there any trick in VS or any tool that I can make use of?
Thanks
Since it's the public properties you wish to save, have a look at Serialization. It allows you to stream an object to a binary format or to XML, and retrieve it later. The stream can be a memory stream or a file, depending on how long you wish to save it. Here is the code from that MSDN page showing how to save an object to an XML file and read it back later:
public class Book
{
public String title;
}
public static void WriteXML()
{
// First write something so that there is something to read ...
var b = new Book { title = "Serialization Overview" };
var writer = new System.Xml.Serialization.XmlSerializer(typeof(Book));
var wfile = new System.IO.StreamWriter(#"c:\temp\SerializationOverview.xml");
writer.Serialize(wfile, b);
wfile.Close();
}
public void ReadXML()
// Now we can read the serialized book ...
System.Xml.Serialization.XmlSerializer reader =
new System.Xml.Serialization.XmlSerializer(typeof(Book));
System.IO.StreamReader file = new System.IO.StreamReader(
#"c:\temp\SerializationOverview.xml");
Book overview = (Book)reader.Deserialize(file);
file.Close();
Console.WriteLine(overview.title);
}
That said, I am not sure Serialization is the best option if you want to use it to re-create objects in unit tests. Usually, you would create a separate (possibly in-memory) database, or mock out the database interface to return hard-coded objects. For example, suppose you have the following production code:
public interface IDataAccess {
User GetUserById(int userId);
}
public class SqlServerDataAccess : IDataAccess {
public User GetUserById(int userId) {
// ... connect to database and retrieve user
}
}
Then for your unit test you may write an implementation
public class MockDataAccess : IDataAccess {
public User GetUserById(int userId) {
return new User() {
Name = "pencilCake", ...
}
}
}
and use that for your unit tests. There are even frameworks like Moq and Rhino that will allow you to create such interfaces "on-the-fly", allowing you to return a specific hardcoded object for every test method.

Good To Use Classes to Create Dummy Data for Unit Tests?

I am trying to do some unit tests and I need dummy data. Some of this data I need to have specific values, other will be just random.
I have for instance a "CreateProduct" method in my Service Layer and I am wondering if it is a good idea to use such methods instead of making a product by hand in my unit tests.
On the surface this seems like a good idea but I am worried maybe I will need to mocking or something to successfully get through that method.
The CreateProduct will try to save the product to the database but I have already a flag that will stop the save happening(used for unit of work scenario encase of rollbacks).
I am using EF 6-rc1 and mocking up the DataContext with moq and I was going to use AutoFixture but it does not work out of box for this secnario and I am starting to feel I am taking too much new tools on at once so maybe I should just do it manually for now.
It's hard to tell exactly what you are doing without a code example, but I sometimes use this implementation of an IDataSet that uses a List in memory. Typical usage would be something like:
using System.Data.Entity;
using System.Linq;
using Moq;
using NUnit.Framework;
namespace EFMock
{
internal interface IDataContext
{
IDbSet<DataItem> DataItems { get; set; }
}
class DataContext : DbContext, IDataContext
{
public IDbSet<DataItem> DataItems{ get; set; }
}
class DataItem
{
public int SomeNumber { get; set; }
public string SomeString { get; set; }
}
/* ----------- */
class DataUsage
{
public int DoSomething(IDataContext dataContext)
{
return dataContext.DataItems.Sum(x => x.SomeNumber);
}
}
/* ----------- */
[TestFixture]
class TestClass
{
[Test]
public void SomeTest()
{
var fakeDataItems = new [] {
new DataItem { SomeNumber = 1, SomeString = "One" },
new DataItem { SomeNumber = 2, SomeString = "Two" }};
var mockDataContext = new Mock<IDataContext>();
mockDataContext.SetupGet(x => x.DataItems).Returns(new FakeDbSet<DataItem>(fakeDataItems));
var dataUsage = new DataUsage();
var result = dataUsage.DoSomething(mockDataContext.Object);
Assert.AreEqual(2, result);
}
}
}
I also have a NuGet package named "FakeO" that you can use to create some fake objects, where some data is a specific value and some is random:
var fakeDataItems = FakeO.Create.Fake<DataItem>(10, // create an IEnumerable of 10 items
x => x.SomeNumber = FakeO.Number.Next(), // set to a random number
x => x.SomeString = "Always This String"); // set to a specific string
One thing to keep in mind with this kind of testing is that using an IQueryable against a List will use Linq2Objects and not Linq2Entities, so results of some Linq queries will be different.
If you want to Unit Test something, you'll just want to test the unit. If you use a method in the servicelayer to generate some fake data, the unit test is not only testing the unit under test, but also the method in the service layer.
So the answer to your question: no, it is not a good idea to use the service layer to dummy data

Methods for Adding Data to Mock DBs in C# Unit Tests

This post is meant to be more a discussion-starter, as I am somewhat new to unit testing and TDD.
I am currently writing some unit tests for a .NET process that interacts with several databases, and am using mock database contexts in an attempt to cover different edge cases within my tests, verify exception handling in the program itself, among other things. That being said, some of my unit tests use valid data, while others do not.
I am looking for feedback in terms of suggested best practices when adding valid/fake data to your mock database contexts. I've seen people do this a number of ways (e.g. - implement repository pattern, adding mock data to .csv files and making them part of the project, etc...).
I'm currently thinking about using a repository pattern for adding Survey objects to the Surveys table in my target DB.
First off, I've got the interface:
public interface ISurveyRepository
{
IQueryable<Survey> SurveySeries { get; }
}
This is implemented both for the mocking fake/valid data repositories as needed by unit tests
class FakeSurveyRepository : ISurveyRepository
{
private static IQueryable<Survey> fakeSurveySeries = new List<Survey> {
new Survey { id = 1, SurveyName="NotValid1", SurveyData="<data>fake</data>"},
new Survey { id = 2, SurveyName="NotValid2", SurveyData="<data>super fake</data>"},
.........,
new Survey {id = 10, SurveyName="NotValid10", SurveyData="<data>the fakest</data>" }
}.AsQueryable();
public IQueryable<Survey> SurveySeries
{
get { return fakeSurveySeries; }
}
}
// RealSurveyRepository : ISurveyRepository is similar to this, but with "good" data
I then have a class to consume this data for either fake/valid data by being passed a reference to the series in the constructor:
public class SurveySeriesProcessor
{
private ISurveyRepository surveyRepository;
public SurveySeriesProcessor( ISurveyRepository surveyRepository )
{
this.surveyRepository = surveyRepository;
}
public IQueryable<Survey> GetSurveys()
{
return surveyRepository.SurveySeries
}
}
And can then approach using these objects in my tests such as:
[TestClass]
public class SurveyTests
{
[TestMethod]
WhenInvalidSurveysFound_SurveyCopierThrowsInvalidSurveyDataErrorForEach()
{
// create mocking DB context and add fake data
var contextFactory = new ContextFactory( ContextType.Mocking );
var surveySeriesProcessor = new SurveySeriesProcessor( new FakeSurveyRepository() );
foreach(Survey surveyRecord in surveySeriesProcessor.GetSurveys() )
{
contextFactory.TargetDBContext.Surveys.AddObject( surveyRecord );
}
// instantiate object being tested and run it against fake test data
var testSurveyCopier = new SurveyCopier( contextFactory );
testSurveyCopier.Start();
// test behavior
List<ErrorMessage> errors = testSurveyCopier.ErrorMessages;
errors.Count.ShouldEqual( surveySeriesProcessor.GetSurveys().Count );
foreach(ErrorMessage errMsg in errors)
{
errMsg.ErrorCode.ShouldEqual(ErrorMessage.ErrorMessageCode.InvalidSurveyData);
}
}
}
NOTE: I realize that in the example code provided I don't necessarily need to make the classes implementing ISurveyRepository return the series as an IQueryable<Survey> (they could very well be List<Survey>). However, I am going to extend the functionality of the interface and these classes in the future to filter out the fake/valid series based on certain criteria added to LINQ queries, which is why I made the repositories implement IQueryable<>. This is mock-up code designed to convey the basic principles of what I'm thinking.
With all of this in mind, what I'm asking is:
Do you have any suggestions in terms of alternative approaches I could take in such scenarios?
What methods have you employed in the past, what did you like/not like about them? Which have you found were the easiest to maintain?
Given what I've posted, do you notice flaws in my general approach to unit testing? Sometimes I feel as though I write unit tests that attempt to cover too much ground instead of being concise, elegant, and to-the-point.
This is meant to be somewhat of an open discussion. Please keep in mind, this is the first set of unit tests I've ever written (I've read a decent amount of literature on the subject, however).
I think you're on a good track.
Personally, in the same situation, if I were dealing with a repository style pattern,
public interface IRepository<T>
{
IEnumerable<T> GetAll();
}
public class PonyRepository : IRepository<Pony>
{
IEnumerable<Pony> GetAll();
}
To actually supply me the data I need, I generally create a TestObjects or TestFakes class to supply the required data on-demand.
public class FakeStuff
{
public static IEnumerable<Pony> JustSomeGenericPonies(int numberOfPonies)
{
// return just some basic list
return new List<Pony>{new Pony{Colour = "Brown", Awesomeness = AwesomenessLevel.Max}};
// or could equally just go bananas in here and do stuff like...
var lOfP = new List<Pony>();
for(int i = 0; i < numberOfPonies; i++)
{
var p = new Pony();
if(i % 2 == 0)
{
p.Colour = "Gray";
}
else
{
p.Colour = "Orange";
}
lOfP.Add(p);
}
return lOfP;
}
}
And test with this as such:
[Test]
public void Hello_I_Want_to_test_ponies()
{
Mock<IRepository<Pony> _mockPonyRepo = new Mock<IRepository<Pony>>();
_mockPonyRepo.SetUp(m => m.GetAll()).Returns(FakeStuff.JustSomeGenericPonies(50));
// Do things that test using the repository
}
So this delivers reusability of the fake data, by keeping it out of the repository and in a place of it's own, meaning I can call this list of ponies anywhere a test requires a list of ponies, not just where a repository is involved.
If I need specific data for a specific testcase, i'll implement something like you had, but be a bit more explicit about what that particular Fake repository is for:
public class FakePonyRepositoryThatOnlyReturnsBrownPonies : IRepository<Pony>
{
private List<Pony> _verySpecificAndNotReusableListOfOnlyBrownPonies = new List....
public IEnumerable<Pony> GetAll()
{
return _verySpecificAndNotReusableListOfOnlyBrownPonies;
}
}
public class FakePonyRepositoryThatThrowsExceptionFromGetAll : IRepository<Pony>
{
public IEnumerable<Pony> GetAll()
{
throw new OmgNoPoniesException();
}
}
You mentioned CSV files as well - this could be viable (have used XML in the past), but I'd argue that holding fake data in a CSV or XML is just a worse version of keeping data in a localised DB using SQL CE or some equivalent. However, both of those are less maintainable and, crucially, in terms of unit tests, slower than using in-memory fake objects. I personally wouldn't use a file-based approach anymore unless I was specifically testing serialization or IO or something.
Hope there's something useful among all that lot...

When to use Mock's Callback versus Return?

I have, what I think, is a pretty straight forward setup in which a search type is created and passed through a service layer and into a repository where a list of a domain type is returned. The search type does nothing but construct an expression tree in the repository method and basically the results from the database come back. Pretty simple
The repository interface:
public interface IDoNotSolicitRepo
{
IList<DNSContract> SelectWithCriteria(DNS_Search searchriteria);
}
The service implementing the repository:
public class DoNotSolicitService : BaseBLLService, IDoNotSolicitService
{
private readonly IDoNotSolicitRepo repo;
private readonly IPartnerService partnerService;
private readonly IDoNotSolicitReasonService dnsReasonSvc;
public DoNotSolicitService(IDoNotSolicitRepo _repo, IPartnerService _partnerSvc, IDoNotSolicitReasonService _dnsReasonSvc)
{
repo = _repo;
partnerService = _partnerSvc;
dnsReasonSvc = _dnsReasonSvc;
}
public ServiceResult<DNSContract> SelectWithCriteria(DNS_Search searchriteria)
{
var results = repo.SelectWithCriteria(searchriteria);
return ReturnServiceResult(results);
}
}
I'm working on learning Moq with this project and I can't figure out if I'm supposed to use a Callback() or a Return(). I get the overall points of both, but neither seem to work properly for me at this moment.
The test:
[Test]
public void SelectWithCriteria_FirstName()
{
mockRepository.Setup(mr => mr.SelectWithCriteria(It.IsAny<DNS_Search>()))
.Returns((IList<DNSContract> records) => new List<DNSContract>
{
new DNSContract {FirstName = "unit", LastName = "test"},
new DNSContract {FirstName = "moq", LastName = "setup"}
});
dnsSvc = new DoNotSolicitService(mockRepository.Object, new PartnerServiceStub(), new DoNotSoicitReasonServiceStub());
var result = dnsSvc.SelectWithCriteria(new DNS_Search { FirstName = "unit" });
Assert.IsNotNull(result);
Assert.IsTrue(result.Data.Any());
}
The error:
System.ArgumentException was unhandled by user code
Message=Object of type 'EP.Rest.Common.RestHelpers.DNS_Search' cannot be converted to type 'System.Collections.Generic.IList`1[EP.Rest.Domain.Contracts.DNSContract]'.
Now, I've read that the Returns() method returns the type passed in, so I can see that's the cause of that error. But in the real world I want the different type returned. I've attempted to create a callback delegate but none of that felt right.
Just drop the lambda on .Returns i.e.
.Returns(new List<DNSContract>());
Your original is passing in arguments from your method to the returns to parameterize the results eg if pulling from a source that can return different data depending on input.
Or
.Returns<IList<DNSContract>>(new List<DNSContract>(){...});

Categories

Resources