I would like to add logic to check if the agent name is already created and alert the user. I created this IQueryable SearchAgents which takes in a string query and I was going to add it to the controller but I am not sure if this is the correct way.
Is this the correct path for validating an agent is already in the system?
AgentController
[HttpPost]
[ApplicationApiAuthorize("Administrator, ContentManager")]
public IHttpActionResult CreateAgent([FromBody]AgentModel agentModel)
{
LogHelper.Info($"Creating agent {agentModel.Name}");
//Search if Agent name is in the system
var AgentId = AgentsDataService.SearchAgents.Select(a => new AgentModel {Name = agentModel.Name }).ToList();
var agentEntity = new Agent();
Mapper.DynamicMap(agentModel, agentEntity);
var agentInformationEntities = Mapper.Map<IEnumerable<AgentInformation>>(agentModel.AgentInformations);
agentEntity.AgentInformations = new EntitySet<AgentInformation>();
agentEntity.AgentInformations.AddRange(agentInformationEntities);
var operationResult = AgentsDataService.InsertAgent(agentEntity);
var result = Ok(new
{
Value = Mapper.Map<AgentModel>(operationResult)
});
return result;
}
AgentDataService
public IQueryable<Agent> SearchAgents(string query)
{
return GetAllAgents().Where(a => a.Name.Contains(query)).OrderBy(a => a.Name);
}
Personally since you only want to know if the entity exists in the database or not I would have the following method in the AgentDataService
public bool AgentExists(string agentName)
{
return GetAllAgents().Any(x => x.Name.Equals(agentName, StringComparison.InvariantCultureIgnoreCase));
}
or the async version (Assuming you are using Entity Framework):
public async Task<bool> AgentExistsAsync(string agentName)
{
return await GetAllAgents().AnyAsync(x => x.Name.Equals(agentName, StringComparison.InvariantCultureIgnoreCase));
}
Then you can call this from your controller and inform the user if the agent exists.
Related
I am trying to write a unit test for a method that relies on a dependency which offers a method that accepts an object and modifies it, but does not return it on a "new path", e.g. as a return value or on a by reference parameter.
public class Product
{
public string Name { get; set; }
}
public interface IFixer
{
void Modify(Product product);
}
public class Fixer: IFixer
{
public void Modify(Product product)
{
if (string.IsNullOrEmpty(product.Name))
{
product.Name = "Default";
}
}
}
public class Manager()
{
private readonly IFixer _fixer;
public Manager(IFixer fixer)
{
_fixer = fixer;
}
public bool IsProductNew(int id)
{
var product = GetProduct(id); // Gets an object instance from a repository, e.g. a file or a database, so we can have something to operate on.
_fixer.Modify(product);
return product.Name != "Default";
}
}
So I want to be able to test my Manager class' IsProductNew() method:
var fakeFixer = A.Fake<IFixer>();
var manager = new Manager(fakeFixer);
var isNew = manager.IsProductNew(A<int>._);
Assert.True(isNew);
What I am missing here is: How do I mock the behaviour of IFixer.Modify(), i.e. have it modify a Product object instance?
Answering this effectively is dependent on the definition of GetProduct(id);
If however the IFixer implementation has no knock on effects or undesirable behavior then there really is no need to mock it.
//Arrange
var fixer = new Fixer();
var manager = new Manager(fixer);
//Act
var isNew = manager.IsProductNew(1);
//Assert
Assert.True(isNew);
But to answer
How do I mock the behaviour of IFixer.Modify(), i.e. have it modify a Product object instance?
you would need a callback that captures the matched parameter
//Arrange
var fakeFixer = A.Fake<IFixer>();
A.CallTo(() => fakeFixer.Modify(A<Product>._))
.Invokes((Product arg) => arg.Name = "Not Default Name");
var manager = new Manager(fakeFixer);
//Act
var isNew = manager.IsProductNew(1);
//Assert
Assert.True(isNew);
Reference Invoking Custom Code
So I want to be able to test my Manager class' IsProductNew() method
You cannot test it effectively in its current form. You will not get 100% coverage. You should either:
pass the product directly:
public bool IsProductNew(Product product)
{
_fixer.Modify(product);
return product.Name != "Default";
}
which you can test by:
var fakeFixer = A.Fake<IFixer>();
var manager = new Manager(fakeFixer);
var product = new Product { Id = 100, Name = "Default" }; // create another test for where Name != "Default"
var isNew = manager.IsProductNew(product);
// Assert that fixer.modify is called with the product
A.CallTo(() => fakeFixer.Modify(A<product>.That.Matches(p => p.Id == 100))).ShouldHaveBeenCalledOnceExactly();
// Should return false because of product name = "Default"
Assert.IsFalse(isNew);
or, pass a "product getter" into the Manager() constructor:
public Manager(IFixer fixer, IProductGetter productGetter)
{
_fixer = fixer;
_productGetter = productGetter;
}
...
public bool IsProductNew(int id)
{
var product = _productGetter.GetProduct(id);
_fixer.Modify(product);
return product.Name != "Default";
}
which you can test by:
var fakeProductGetter = A.Fake<IProductGetter>();
// Prime the product getter to return a product
A.CallTo(() => fakeProductGetter.Get(A<int>.Ignored))
.Returns(new Product{
Id = 100,
Name = "Default" // create another test for where Name != "Default"
});
var fakeFixer = A.Fake<IFixer>();
var manager = new Manager(fakeFixer, fakeproductGetter);
var isNew = manager.IsProductNew(100);
// Assert that a call is made to productGetter.Get with the ID
A.CallTo(() => productGetter.Get(100)).MustHaveHapennedOnceExactly();
// Assert that fixer.modify is called with the product
A.CallTo(() => fakeFixer.Modify(A<product>.That.Matches(p => p.Id == 100))).ShouldHaveBeenCalledOnceExactly();
// Should return false because of product name = "Default"
Assert.IsFalse(isNew);
The choice you make depends on whether you want the IsProductNew() method to be responsible for getting the product by the ID, or if you want to just pass the product directly.
Could some one please help me to resolved this? i'm trying to change CustomAsync to MustAsync, but i couldn't make things to work. Below is my custom method
RuleFor(o => o).MustAsync(o => {
return CheckIdNumberAlreadyExist(o)
});
private static async Task<ValidationFailure> CheckIdNumberAlreadyExist(SaveProxyCommand command)
{
if (command.Id > 0)
return null;
using (IDbConnection connection = new SqlConnection(ConnectionSettings.LicensingConnectionString))
{
var param = new DynamicParameters();
param.Add("#idnumber", command.IdNumber);
var vehicle = await connection.QueryFirstOrDefaultAsync<dynamic>("new_checkDuplicateProxyIdNumber", param, commandType: CommandType.StoredProcedure);
return vehicle != null
? new ValidationFailure("IdNumber", "Id Number Already Exist")
: null;
}
}
To make it work with the latest version of the FluentValidation, I had to use the codes like below.
RuleFor(ws => ws).MustAsync((x, cancellation) => UserHasAccess(x)).WithMessage("User doesn't have access to perform this action");
Please notice the lambda expression here MustAsync((x, cancellation) => UserHasAccess(x)), without this I was always getting an error as cannot convert from 'method group' to 'Func<Worksheet, CancellationToken, Task<bool>>
Below is my custom UserHasAccess function.
private async Task <bool> UserHasAccess(Worksheet worksheet) {
var permissionObject = await _dataProviderService.GetItemAsync(worksheet.FileItemId);
if (permissionObject is null) return false;
if (EditAccess(permissionObject.Permission)) return true;
return false;
}
I'm assuming you're using a version of FluentValidation prior to version 6, as you're not passing in a Continuation Token, so I've based my answer on version 5.6.2.
Your example code does not compile, for starters, as you're missing a semi-colon in your actual rule. You are also evaluating two different properties on the SaveProxyCommand parameter.
I've built a very small POC based on some assumptions:
Given 2 classes:
public class SaveProxyCommand {
public int Id { get; set; }
}
public class ValidationFailure {
public string PropertyName { get; }
public string Message { get; }
public ValidationFailure(string propertyName, string message){
Message = message;
PropertyName = propertyName;
}
}
And a validator:
public class SaveProxyCommandValidator : AbstractValidator<SaveProxyCommand>{
public SaveProxyCommandValidator()
{
RuleFor(o => o).MustAsync(CheckIdNumberAlreadyExists)
.WithName("Id")
.WithState(o => new ValidationFailure(nameof(o.IdNumber), "Id Number Already Exist"));
}
private static async Task<bool> CheckIdNumberAlreadyExists(SaveProxyCommand command) {
if (command.Id > 0)
return true;
var existingIdNumbers = new[] {
1, 2, 3, 4
};
// This is a fudge, but you'd make your db call here
var isNewNumber = !(await Task.FromResult(existingIdNumbers.Contains(command.IdNumber)));
return isNewNumber;
}
}
I didn't include the call to the database, as that's not part of your problem. There are a couple of things of note here:
You're not setting the .WithName annotation method, but when you're setting up a validation rule for an object you have to do this, as FluentValidation expects you to specify specific properties to be validated by default, if you pass in an entire object it just doesn't know how to report errors back.
Must/MustAsync need to return a bool/Task<bool> instead of a custom object. To get around this, you can specify a custom state to be returned when failing validation.
You can then get access to this like this:
var sut = new SaveProxyCommand { Id = 0, IdNumber = 3 };
var validator = new SaveProxyCommandValidator();
var result = validator.ValidateAsync(sut).GetAwaiter().GetResult();
var ValidationFailures = result.Errors?.Select(s => s.CustomState).Cast<ValidationFailure>();
The above does not take into account empty collections, it's just an example of how to dig into the object graph to retrieve custom state.
As a suggestion, fluentvalidation works best if you set up individual rules per property, instead of validating the entire object. My take on this would be something like this:
public class SaveProxyCommandValidator : AbstractValidator<SaveProxyCommand>{
public SaveProxyCommandValidator()
{
RuleFor(o => o.IdNumber).MustAsync(CheckIdNumberAlreadyExists)
.Unless(o => o.Id > 0)
.WithState(o => new ValidationFailure(nameof(o.IdNumber), "Id Number Already Exist"));
}
private static async Task<bool> CheckIdNumberAlreadyExists(int numberToEvaluate) {
var existingIdNumbers = new[] {
1, 2, 3, 4
};
// This is a fudge, but you'd make your db call here
var isNewNumber = !(await Task.FromResult(existingIdNumbers.Contains(numberToEvaluate)));
return isNewNumber;
}
}
This read more like a narrative, it uses the .Unless construct to only run the rule if Id is not more than 0, and does not require the evaluation of the entire object.
I am starting with MongoDb on c#. At the end, I need function which simply checks if the user exists in DB -thats it.
I am a complete beginner so naturally example right from MongoDb tutorial does not work
here are examples:
public static async Task<List<User>> QueryDB(User u)
{
var collection = _database.GetCollection<User>("UserData");
var filter = Builders<User>.Filter.Eq("id", u.id);
var result = await collection.Find(filter).ToListAsync();
return result;
}
or
public static async Task<long> QueryDB(User u)
{
var collection = _database.GetCollection<User>("UserData");
var filter = Builders<User>.Filter.Eq("id", u.id);
var result = await collection.Find(filter).CountAsync();
return result;
}
What is wrong with these functions? Or how should I call them? Because now it throws a timeout.
Can this be done without async/await? I think I don't need it
I would suggest using FindAsync, it works better and you prevent deadlocks in c# and let mongo do its job.
public async Task<List<User>> QueryDB(User u)
{
var collection = _database.GetCollection<User>("UserData");
var filter = Builders<User>.Filter.Eq(us => us.id, u.id); //best practice to prevent errors on field name such as extra letter or capital vs lowercase.
List<User> fetchedUsers = new List<User>()
using (var cursor = await collection.FindAsync(filter))
{
while (await cursor.MoveNextAsync())
{
var batch = cursor.Current;
foreach (User user in batch)
fetchedUsers.Add(user);
}
}
return fetchedUsers;
}
if you want to "advance" you can use this method to all classes that have id field
public async Task<List<T>> QueryDB(this IMongoCollection<T> collection, T entity) where T : Idable
{
var filter = Builders<T>.Filter.Eq(ts => ts.id, entity.id);
List<T> fetchedData = new List<T>()
using (var cursor = await collection.FindAsync(filter))
{
while (await cursor.MoveNextAsync())
{
var batch = cursor.Current;
foreach (T res in batch)
fetchedData.Add(res);
}
}
return fetchedData;
}
interface Idable
{
string id {get;};
}
public class User : Idable
{
...
}
you simply have this method "attached" to all your collections now.
just create a list, lets say type of User, and call the collection.QueryDB(User u) and you will get a list of all users with the same id, yes..probably only 1, but you can modify this method and just play with it.
I am using database with multiple language support. Now the problem is that I need to enter my language into query in order to get information and it is fine, but what would be optimal way to store that information.
On client side it will be stored in cookies, of course. Now only way I can think of is making global variable on class and then use it in my functions. Is that only way?
Example code
private string lang = Infrastructure.UserSettings.Language(); // I don't have this implemented yet
[HttpGet]
public dynamic List()
{
string lang = "English"; // That's why I set it here manually for testing
var items = _db.Items.OrderByDescending(x => x.ID).Select(x => new
{
ID = x.ID,
Price = x.Price,
Name = x.ItemTranslations.Where(y => y.Language.Name == lang).Select(y => y.Name).SingleOrDefault(),
Category = new {
ID = x.Category.ID,
Name = x.Category.CategoryTranslations.Where(y => y.Language.Name == lang).Select(y => y.Name).SingleOrDefault()
}
});
return items;
}
My question: Is this good way of doing this or there is some more optimal way?
You could make a base controller with a read-only variable, like so:
public class BaseController : Controller
{
public string UserLanguage
{
get
{
var cLanguage = HttpContext.Request.Cookies["lang"];
if (cLanguage != null)
return cLanguage.Value;
else
return "English";
}
}
}
Then inherit your base controller, like so:
public class HomeController : BaseController
Then access your variable like so:
var items = _db.Items.OrderByDescending(x => x.ID).Select(x => new
{
ID = x.ID,
Price = x.Price,
Name = x.ItemTranslations.Where(y => y.Language.Name == UserLanguage).Select(y => y.Name).SingleOrDefault(),
Category = new {
ID = x.Category.ID,
Name = x.Category.CategoryTranslations.Where(y => y.Language.Name == lang).Select(y => y.Name).SingleOrDefault()
}
});
You would just need to set the cookie at a particular time.
A cookie is sent to the server on every page request. If the setting is available in the cookie, just read the cookie when you need to do a query. There is no performance overhead for reading a cookie that is already present.
So the scenario is this: a user does some action (like earn a badge or unlock something) and an email notification gets sent out. One to the user (with a message like "You've unlocked XYZ...") and then a different message to each of their friends like ("You're friend has unlocked XYZ...").
public interface INotify
{
void Notify(User user, User friend);
}
public class NotificationService
{
private IEnumerable<INotify> _notifiers;
public NotificationService(IEnumerable<INotify> notifiers)
{
_notifiers = notifiers;
}
public SendNotifications()
{
User user = GetUser();
IEnumerable<User> friends = GetFriends();
foreach(var notifier in _notifiers)
{
//Send notification to user
notifier.Notify(user, null);
//send notification to users friends
foreach(var friend in friends)
notifier.Notify(user, friend);
}
}
}
I'm trying to use moq to test that each notifier is called 2x. Once passing null as the second parameter and the second time passing in a value to both parameters.
[Test]
public void MakeSureEveryoneIsNotified()
{
var notifierMock = new Mock<INotifier>();
var svc = new NotificationService(new List<INotifier>{ notifierMock.Object });
svc.SendNotifications();
notifierMock.Verify(x => x.Notify(It.Is<User>(user => user.UserId == 1), null), Times.Once());
notifierMock.Verify(x => x.Notify(It.Is<User>(user => user.UserId == 1), It.Is<User>(user => user.UserId == 2)), Times.Once());
}
The problem is that the second verify call throws an ArgumentNullException for the second parameter. Is there away to say "Check the first call has these parameters, and then the second call has other parameters". I know I can get it around it simply by calling:
notifierMock.Verify(x => x.Notify(It.IsAny<User>(), It.IsAny<User>()), Times.Exactly(2));
But I was wanting to be a little more specific. Anyway to do this?
You can achieve this by recording what happens on each call to Notify. Then you can compare the recording to what's expected:
[TestMethod]
public void TestMoqInvocations()
{
var notifierMock = new Mock<INotifier>();
var svc = new NotificationService(new List<INotifier>{ notifierMock.Object });
svc.SendNotifications();
var invocations = new List<NotifyParams>();
notifierMock
.Setup(f => f.Notify(It.IsAny<User>(), It.IsAny<User>()))
.Callback<string, string>((user, friend) => invocations.Add(new NotifyParams{user = user, friend = friend}));
Assert.AreEqual(1, invocations[0].user.UserId);
Assert.IsNull(invocations[0].friend);
Assert.AreEqual(1, invocations[1].user.UserId);
Assert.AreEqual(2, invocations[1].user.UserId);
}
public struct NotifyParams {
public User user {get;set;}
public User friend { get; set; }
}
You can create a method for get User list. Then get user by It.Is method.
private bool GetUser(User user, List<User> users)
{
if (user != null)
users.Add(user);
return true;
}
[Test]
public void MakeSureEveryoneIsNotified()
{
var notifierMock = new Mock<INotifier>();
var svc = new NotificationService(new List<INotifier>{ notifierMock.Object });
svc.SendNotifications();
var users = new List<User>();
var friends = new List<User>();
// verify how many times call the method
notifierMock
.Verify(x => x.Notify(
It.Is<User>(u => GetUser(u, users)),
It.Is<User>(f => GetFriend(f, friends))
), Times.Exactly(2));
Assert.AreEquals(2, users.Count);
Assert.AreEquals(1, users[0].UserId);
Assert.AreEquals(1, users[1].UserId);
Assert.AreEquals(1, friends.Count);
Assert.AreEquals(2, friends[0].UserId);
}