I am new to Moq having used Rhino mocks for a while. I am trying to stub a method so that is returns the information I expect but the actual line of code when running the test returns a null reference exception. Am I missing something obvious here? Below is my code:
public void GetResSystemClients(ResSystem resSystem)
{
ResSystemDetail = new ResSystemDetails() {ResSys = resSystem};
//RETURNS NULL REFERENCE EXCEPTION
var resClients = FileReader.ReadFile((c) => c.Where(x =>
x.ReservationSystem.Replace(" ", "").ToLowerInvariant().Contains(resSystem.ToString().ToLowerInvariant())));
ResSystemDetail.ResSystemClients = resClients
.Select(y => new ResSystemClient() {ClientCode = y.ClientCode, ClientName = y.ClientName})
.OrderBy(z => z.ClientCode).ToList();
}
Test Code
[SetUp]
public void SetUp()
{
mockFileReader = new Mock<IClientLookUpFileReader>(MockBehavior.Default);
sut = new ClientLookupModel();
}
[TestCase(ResSystem.Test)]
public void When_GetResSystemCalled_With_ResSystem_Return_CorrectClients(ResSystem system)
{
//Arrange
mockFileReader.Setup(x =>
x.ReadFile(It.IsAny<Func<List<ExtraClientInfo>, IEnumerable<ExtraClientInfo>>>()))
.Returns(new List<ExtraClientInfo>
{
new ExtraClientInfo
{
ClientName = "Test",
ClientCode = "XX"
},
new ExtraClientInfo
{
ClientName = "Test1",
ClientCode = "X1"
},
new ExtraClientInfo
{
ClientName = "Test2",
ClientCode = "X2"
},
});
//Act
sut.GetResSystemClients(system);
}
Read file code
public interface IClientLookUpFileReader
{
T ReadFile<T>(Func<List<ExtraClientInfo>, T> predicateFunc);
}
public class ClientLookUpFileReader : IClientLookUpFileReader
{
private const string filePath = "D:/PersistedModels/ClientInfo.json";
T IClientLookUpFileReader.ReadFile<T>(Func<List<ExtraClientInfo>, T> predicateFunc)
{
if (File.Exists(filePath))
{
var clientInfoList = new JavaScriptSerializer().Deserialize<List<ExtraClientInfo>>(System.IO.File.ReadAllText(filePath));
return predicateFunc(clientInfoList);
}
throw new Exception($"File not found at path {filePath}");
}
}
Related
I am trying to write down unit test for my repository which is interacting with MongoDb but facing a problem/exception in mocking the objects. This is what I have tried so far;
This is how my class looks like i.e. I have create a repository class and extend it from interface;
public class UserManagementRepository : IUserManagementRepository
{
private readonly IMongoCollection<UserModel> _users;
public UserManagementRepository(IDatabaseSettings dbSettings, IApplicationSettings applicationSettings, IMongoClient mongoClient)
{
IMongoDatabase database = mongoClient.GetDatabase(dbSettings.DatabaseName);
_users = database.GetCollection<UserModel>(applicationSettings.UserCollectionName);
}
public async Task<GeneralResponse> Get(string id)
{
GeneralResponse response = new GeneralResponse();
try
{
IAsyncCursor<UserModel> userModel = await _users.FindAsync(user => user.Id == id);
if (userModel != null)
{
response.Message = "User exists!";
response.Data = userModel.FirstOrDefault();
response.ResponseCode = ResponseCode.Success;
}
else
{
response.Message = $"User with Id: {id} not found!";
response.ResponseCode = ResponseCode.Success;
}
}
catch (Exception ex)
{
response.Message = "Failure";
response.ResponseCode = ResponseCode.Error;
}
return response;
}
}
This is how my Test class look like
public class UserManagmentRepositoryTests
{
private Mock<IDatabaseSettings> _mockDbSettings;
private Mock<IApplicationSettings> _mockApplicationSettings;
private Mock<IMongoClient> _mockClient;
public UserManagmentRepositoryTests()
{
_mockDbSettings = new Mock<IDatabaseSettings>();
_mockApplicationSettings = new Mock<IApplicationSettings>();
_mockClient = new Mock<IMongoClient>();
}
[Fact]
public async Task GetUserWithId_Test()
{
// Arrange
var repo = new Mock<IUserManagementRepository>();
IDatabaseSettings dbSettings = new DatabaseSettings()
{
ConnectionString = "mongodb:connectionstring",
DatabaseName = "dbname"
};
_mockDbSettings.Setup(x => x).Returns(dbSettings);
IApplicationSettings applicationSettings = new ApplicationSettings() { UserCollectionName = "users" };
_mockApplicationSettings.Setup(app => applicationSettings).Returns(applicationSettings);
MongoClientSettings clientSettings = MongoClientSettings.FromConnectionString(dbSettings.ConnectionString);
MongoClient client = new MongoClient(clientSettings);
_mockClient.Setup(c => client);
var ctr = new UserManagementRepository(_mockDbSettings.Object, _mockApplicationSettings.Object, _mockClient.Object);
// Act
var result = ctr.Get("132");
// Assert
//result.StatusCode.Should().NotBeNull();
}
}
I get an exception on every setup
You are trying to use ApplicationSettings as an expression. The setup method expects you to provide an expression for when to activate the mocked override.
In your case just get rid of the Mock<IApplicationSettings> altogether and mock all the objects you need to call any methods on:
[Fact]
public async Task GetUserWithId_Test()
{
// Arrange
var userModel = new UserModel() { Id = "123" };
var mockCursor = new Mock<IAsyncCursor<UserModel>>();
mockCursor
.Setup(c => c.FirstOrDefault())
.Returns(userModel);
var mockCollection = new Mock<IMongoCollection<UserModel>>();
Predicate<UserModel> filter = u => u.Id == userModel.Id;
mockCollection
.Setup(c => c.FindAsync(filter))
.ReturnsAsync(mockCursor.Object);
var mockDb = new Mock<IMongoDatabase>();
mockDb
.Setup(db => db.GetCollection<UserModel>(It.IsAny<string>()))
.Returns(mockCollection.Object);
_mockClient
.Setup(c => c.GetDatabase(It.IsAny<string>()))
.Returns(mockDb.Object)
var ctr = new UserManagementRepository(new(), new(), _mockClient.Object);
// Act
var result = ctr.Get("132");
// Assert
result.StatusCode.Should().Be(ResponseCode.Success);
result.Message.Should().Be("User exists!");
result.Data.Should().Be(userModel);
}
Hope this helps a little 🙂
To use your ApplicationSettings as mocked ApplicationSettings, you must use an expression in the setup method.
Instead of:
IApplicationSettings applicationSettings = new ApplicationSettings() { UserCollectionName = "users" };
_mockApplicationSettings.Setup(app => applicationSettings).Returns(applicationSettings);
Use e.g. this:
IApplicationSettings applicationSettings = new ApplicationSettings() { UserCollectionName= "users" };
_mockApplicationSettings.Setup(app => app.UserCollectionName).Returns(applicationSettings.UserCollectionName);
Edit: Complete Example
private Mock<IDatabaseSettings> _mockDbSettings;
private Mock<IApplicationSettings> _mockApplicationSettings;
private Mock<IMongoClient> _mockClient;
public UserManagmentRepositoryTests()
{
_mockDbSettings = new Mock<IDatabaseSettings>();
_mockApplicationSettings = new Mock<IApplicationSettings>();
_mockClient = new Mock<IMongoClient>();
}
[Fact]
public async Task GetUserWithId_Test()
{
// Arrange
var repo = new Mock<IUserManagementRepository>();
IDatabaseSettings dbSettings = new DatabaseSettings()
{
ConnectionString = "mongodb:connection",
DatabaseName = "dbname"
};
_mockDbSettings.Setup(x => x.ConnectionString).Returns(dbSettings.ConnectionString);
_mockDbSettings.Setup(x => x.DatabaseName).Returns(dbSettings.DatabaseName);
IApplicationSettings applicationSettings = new ApplicationSettings() { UserCollectionName = "users" };
_mockApplicationSettings.Setup(app => app.UserCollectionName).Returns(applicationSettings.UserCollectionName);
MongoClientSettings clientSettings = MongoClientSettings.FromConnectionString(dbSettings.ConnectionString);
MongoClient client = new MongoClient(clientSettings);
_mockClient.Setup(c => c.GetDatabase(It.IsAny<string>(), It.IsAny<MongoDatabaseSettings>()))
.Returns <string, MongoDatabaseSettings>((name, settings) => client.GetDatabase(name, settings));
var ctr = new UserManagementRepository(_mockDbSettings.Object, _mockApplicationSettings.Object, _mockClient.Object);
// Act
var result = await ctr.Get("132");
// Assert
result.ResponseCode.Should().NotBe(ResponseCode.Error);
}
I see no reason mocking IApplicationSettings and IDatabaseSettings you should go with :
public class UserManagmentRepositoryTests
{
private Mock<IMongoClient> _mockClient;
public UserManagmentRepositoryTests()
{
_mockClient = new Mock<IMongoClient>();
}
[Fact]
public async Task GetUserWithId_Test()
{
// Arrange
var repo = new Mock<IUserManagementRepository>();
IDatabaseSettings dbSettings = new DatabaseSettings()
{
ConnectionString = "mongodb:connectionstring",
DatabaseName = "dbname"
};
IApplicationSettings applicationSettings = new ApplicationSettings() { UserCollectionName = "users" };
MongoClientSettings clientSettings = MongoClientSettings.FromConnectionString(dbSettings.ConnectionString);
MongoClient client = new MongoClient(clientSettings);
_mockClient.Setup(c => client);
var ctr = new UserManagementRepository(dbSettings, applicationSettings, _mockClient.Object);
// Act
var result = ctr.Get("132");
// Assert
//result.StatusCode.Should().NotBeNull();
}
}
public class UserService
{
IUserRepo userRepo;
UserService(IUserRepo repo)
{
userRepo = repo;
}
void AddUser(JsonData data)
{
User user = new User()
{
Name = data.name,
Number = data.Number
};
userRepo.Insert(user);
int id = user.id;
}
}
id is 0 when a unit test case is debugged, but when it is a proper call it returns proper primary key i.e. 1, 2, 3, etc.
Mock
class TestCases
{
Mock<IUserRepo> mockUserRepo = new Mock<IUserRepo>();
[Test]
public void test1()
{
//Arrange
JsonData obj = new JsonData()
{
Name = "Jane",
Number = "0563722992"
}
User dumpUser= new User()
{
Name = "Def",
Number = "8111"
};
mockUserRepo
.Setup(x => x.Insert(It.IsAny<User>()))
.Callback(() => dumpUser.Id = 1);
//Act
UserService u = new UserService(mockUserRepo.Object);
u.AddUser(obj);
//Assert
}
}
While debugging the unit test it seems that callback is unable to change the id to 1 when it passes through the method Insert().
Can anybody help how to tackle with this issue?
There is no need for
User dumpUser= new User()
{
Name = "Def",
Number = "8111"
};
As the method under test creates/initializes it's own instance within.
Capture the passed argument in the call back and update the desired member there
//...
userRepo
.Setup(x => x.Insert(It.IsAny<User>()))
.Callback((User arg) => arg.Id = 1);
//...
I would like to pass an object and expression into a dynamically created workflow to mimic the Eval function found in many languages. Can anyone help me out with what I am doing wrong? The code below is a very simple example if taking in a Policy object, multiple its premium by 1.05, then return the result. It throws the exception:
Additional information: The following errors were encountered while processing the workflow tree:
'DynamicActivity': The private implementation of activity '1: DynamicActivity' has the following validation error: Value for a required activity argument 'To' was not supplied.
And the code:
using System.Activities;
using System.Activities.Statements;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Policy p = new Policy() { Premium = 100, Year = 2016 };
var inputPolicy = new InArgument<Policy>();
var theOutput = new OutArgument<object>();
Activity dynamicWorkflow = new DynamicActivity()
{
Properties =
{
new DynamicActivityProperty
{
Name="Policy",
Type=typeof(InArgument<Policy>),
Value=inputPolicy
}
},
Implementation = () => new Sequence()
{
Activities =
{
new Assign()
{
To = theOutput,
Value=new InArgument<string>() { Expression = "Policy.Premium * 1.05" }
}
}
}
};
WorkflowInvoker.Invoke(dynamicWorkflow);
}
}
public class Policy
{
public int Premium { get; set; }
public int Year { get; set; }
}
}
You can use Workflow Foundation to evaluate expressions, but it is far easier to use almost any other option.
The key issue at play with your code was that you were not trying to evaluate the expression (with either VisualBasicValue or CSharpValue). Assigning InArgument`1.Expression is an attempt to set the value - not to set the value to the result of an expression.
Keep in mind that compiling expressions is fairly slow (>10ms), but the resultant compiled expression can be cached for quick executions.
Using Workflow:
class Program
{
static void Main(string[] args)
{
// this is slow, only do this once per expression
var evaluator = new PolicyExpressionEvaluator("Policy.Premium * 1.05");
// this is fairly fast
var policy1 = new Policy() { Premium = 100, Year = 2016 };
var result1 = evaluator.Evaluate(policy1);
var policy2 = new Policy() { Premium = 150, Year = 2016 };
var result2 = evaluator.Evaluate(policy2);
Console.WriteLine($"Policy 1: {result1}, Policy 2: {result2}");
}
}
public class Policy
{
public double Premium, Year;
}
class PolicyExpressionEvaluator
{
const string
ParamName = "Policy",
ResultName = "result";
public PolicyExpressionEvaluator(string expression)
{
var paramVariable = new Variable<Policy>(ParamName);
var resultVariable = new Variable<double>(ResultName);
var daRoot = new DynamicActivity()
{
Name = "DemoExpressionActivity",
Properties =
{
new DynamicActivityProperty() { Name = ParamName, Type = typeof(InArgument<Policy>) },
new DynamicActivityProperty() { Name = ResultName, Type = typeof(OutArgument<double>) }
},
Implementation = () => new Assign<double>()
{
To = new ArgumentReference<double>() { ArgumentName = ResultName },
Value = new InArgument<double>(new CSharpValue<double>(expression))
}
};
CSharpExpressionTools.CompileExpressions(daRoot, typeof(Policy).Assembly);
this.Activity = daRoot;
}
public DynamicActivity Activity { get; }
public double Evaluate(Policy p)
{
var results = WorkflowInvoker.Invoke(this.Activity,
new Dictionary<string, object>() { { ParamName, p } });
return (double)results[ResultName];
}
}
internal static class CSharpExpressionTools
{
public static void CompileExpressions(DynamicActivity dynamicActivity, params Assembly[] references)
{
// See https://learn.microsoft.com/en-us/dotnet/framework/windows-workflow-foundation/csharp-expressions
string activityName = dynamicActivity.Name;
string activityType = activityName.Split('.').Last() + "_CompiledExpressionRoot";
string activityNamespace = string.Join(".", activityName.Split('.').Reverse().Skip(1).Reverse());
TextExpressionCompilerSettings settings = new TextExpressionCompilerSettings
{
Activity = dynamicActivity,
Language = "C#",
ActivityName = activityType,
ActivityNamespace = activityNamespace,
RootNamespace = null,
GenerateAsPartialClass = false,
AlwaysGenerateSource = true,
ForImplementation = true
};
// add assembly references
TextExpression.SetReferencesForImplementation(dynamicActivity, references.Select(a => (AssemblyReference)a).ToList());
// Compile the C# expression.
var results = new TextExpressionCompiler(settings).Compile();
if (results.HasErrors)
{
throw new Exception("Compilation failed.");
}
// attach compilation result to live activity
var compiledExpression = (ICompiledExpressionRoot)Activator.CreateInstance(results.ResultType, new object[] { dynamicActivity });
CompiledExpressionInvoker.SetCompiledExpressionRootForImplementation(dynamicActivity, compiledExpression);
}
}
Compare to the equivalent Roslyn code - most of which is fluff that is not really needed:
public class PolicyEvaluatorGlobals
{
public Policy Policy { get; }
public PolicyEvaluatorGlobals(Policy p)
{
this.Policy = p;
}
}
internal class PolicyExpressionEvaluator
{
private readonly ScriptRunner<double> EvaluateInternal;
public PolicyExpressionEvaluator(string expression)
{
var usings = new[]
{
"System",
"System.Collections.Generic",
"System.Linq",
"System.Threading.Tasks"
};
var references = AppDomain.CurrentDomain.GetAssemblies()
.Where(a => !a.IsDynamic && !string.IsNullOrWhiteSpace(a.Location))
.ToArray();
var options = ScriptOptions.Default
.AddImports(usings)
.AddReferences(references);
this.EvaluateInternal = CSharpScript.Create<double>(expression, options, globalsType: typeof(PolicyEvaluatorGlobals))
.CreateDelegate();
}
internal double Evaluate(Policy policy)
{
return EvaluateInternal(new PolicyEvaluatorGlobals(policy)).Result;
}
}
Roslyn is fully documented, and has the helpful Scripting API Samples page with examples.
I am creating some unit tests for a controller I have however I ran into a problem.
Basically I have the following:-
The Controller Method :-
[ResponseType(typeof(Attrib))]
public IHttpActionResult GetAttrib(int id)
{
var attrib = _attribsRepository.GetAttrib(id);
if (attrib == null)
{
return NotFound();
}
return Ok(attrib);
}
Its a simple Web API 2.0 method.
Then I have the Repository :-
public Attrib GetAttrib(int id)
{
return DbSet.FirstOrDefault(x=>x.Id == id);
}
And finally the Test Method:-
public class AttribsControllerTests
{
public Mock<IAttribsRepository> _attribsRepositoryMock;
public List<Attrib> AttribList;
public AttribsController AttribsController;
[SetUp]
public void Init()
{
_attribsRepositoryMock = new Mock<IAttribsRepository>();
AttribList = new List<Attrib>
{
new Attrib()
{
Id = 1,
AttributeId = "Cro",
AttributeName = "Crossing",
AttributeType = "Tech",
AttributeValue = 1
},
new Attrib()
{
Id = 2,
AttributeId = "Dri",
AttributeName = "Dribbling",
AttributeType = "Tech",
AttributeValue = 2
},
new Attrib()
{
Id = 3,
AttributeId = "Fin",
AttributeName = "Finishing",
AttributeType = "Tech",
AttributeValue = 3
}
};
}
[Test]
public void Get_Check_That_Id1_Returns_Crossing()
{
//Arrange
_attribsRepositoryMock.Setup(t => t.GetStaticAttribs()).Returns(AttribList.AsQueryable());
//Act
var attribsController = new AttribsController(_attribsRepositoryMock.Object);
var result = attribsController.GetAttrib(1) as OkNegotiatedContentResult<Attrib>;
//Assert
Assert.IsNotNull(result);
Assert.AreEqual(AttribList[0].AttributeName, "Cor");
}
}
For some reason, the result is always null, so its not hitting the controller correctly.
Any ideas why this could happen? When debugging, the correct Mock Repository is hitting the controller, and it should have the 3 entries in it.
Any help will be very much appreciated.
You setup GetStaticAttribs but it is used nowhere in the example you showed. You were suppose to setup IAttribsRepository.GetAttrib
Based on your example
[Test]
public void Get_Check_That_Id1_Returns_Crossing() {
//Arrange
var id = 1;
_attribsRepositoryMock.Setup(t => t.GetAttrib(id)).Returns(AttribList[0]);
var attribsController = new AttribsController(_attribsRepositoryMock.Object);
//Act
var result = attribsController.GetAttrib(id) as OkNegotiatedContentResult<Attrib>;
//Assert
Assert.IsNotNull(result);
Assert.IsNotNull(result.Content);
Assert.AreEqual(result.Content.AttributeName, "Crossing");
}
I have the following code:
var connector = new Mock<IConector>();
connector
.Setup(cn => cn.listar("FetchEstandar", new Estandar(), new {Id = 1}))
.Returns(new List<Estandar>{ new Estandar {Id = 1} });
var entidad = connector.Object
.listar("FetchEstandar", new Estandar(), new {Id = 1});
when I call listar on the connector Object, I get an "Expression Cannot Contain an Anonymouse Type" error. I've tried with rhino mocks and moq.
Is there any way I can mock this method? am I doing something wrong? alternatively, I could ignore this parameter but I don't know how. I really just need to test the value of the first parameter and ignorearguments works but I have no idea whether or how I can get this value if I use it
I do not know if this is the only way to match an anonymous object but it can be done using It.Is<>() and reflection
public class Estandar {
public int Id { get; set; }
}
public interface IConector {
IEnumerable<Estandar> listar(string name, Estandar estandar, object key);
}
[TestMethod]
public void CheckAnonymous() {
var connector = new Mock<IConector>();
connector.Setup(cn => cn.listar("FetchEstandar",
It.IsAny<Estandar>(),
It.Is<object>(it => MatchKey(it, 1))))
.Returns(new List<Estandar> { new Estandar { Id = 1 } });
var entidad = connector.Object.listar("FetchEstandar", new Estandar(), new { Id = 1 });
Assert.AreEqual(1, entidad.Count());
}
public static bool MatchKey(object key, int soughtId) {
var ret = false;
var prop = key.GetType().GetProperty("Id");
if (prop != null) {
var id = (int)prop.GetValue(key, null);
ret = id == soughtId;
}
return ret;
}