I currently have such a Moq expression
repo.Setup(r => r.GetProjectConfigurationById(It.Is<int>(s => s == response.Id)))
.Returns(response); // return response only if id matches setup one
As one can see, response is an object that has its own Id field.
Now I have a List<responses> and would like to transfer this expression into something that behaves as such:
get any integer Id
if Id is mathcing a response.Id, return that element of a list.
optionally, if match is not found, return null
How I could do that with Moq?
You can use the It.IsAny<int>() to match any parameter in GetProjectConfigurationById
There are also overloads of the Returns function where you can specify your custom condition using the parameter passed in to your GetProjectConfigurationById to look up the element by id or return null:
var responses = new List<Response>();
//...
repo.Setup(r => r.GetProjectConfigurationById(It.IsAny<int>()))
.Returns<int>(id => responses.SingleOrDefault(r => r.Id == id));
Related
I am trying to get the Patient's Firstname from a database but what I am getting when I run this piece of code is just a Linq expression string instead.
public static string GetPatientName(int bedNumber)
{
var name = "";
using (var data = new HospitalDBDataContext())
{
if (data.Connection.State == ConnectionState.Closed)
data.Connection.Open();
name = data.Patients.Where(x => x.BedNumber.Equals(bedNumber))
.Select(x => x.Firstname).ToString();
if (data.Connection.State == ConnectionState.Open)
data.Connection.Close();
data.Dispose();
}
return name;
}
What is the way of making this Expression to return the actual value I need?
name = data.Patients.Where(x => x.BedNumber.Equals(bedNumber))
.Select(x => x.Firstname).ToString();
Should be:
name = data.Patients.Where(x => x.BedNumber.Equals(bedNumber))
.Select(x => x.Firstname).FirstOrDefault();
You need to actually select .First() or .FirstOrDefault(). Right now you are casting the entire IQueryable statement into a string.
The problem is ToString call that gives you the Linq expression
possible solutions. using FirstOrDefault to get first name.
name = data.Patients.Where(x => x.BedNumber.Equals(bedNumber)).Select(x => x.Firstname).FirstOrDefault();
Or use string.Join to get all the names in one string with separator like ,(the first parameter passed to string.join).
name = string.Join(", " ,data.Patients.Where(x => x.BedNumber.Equals(bedNumber)).Select(x => x.Firstname));
The Where method returns an Enumerable<T> of results (patients), and the Select method returns a new Enumerable<string> with the Firstnames of each patient.
Instead of converting that Enumerable<string> to a string, you need to use a method like Single or First to get one object out of it.
(Single will throw an exception if there is more than one object in the Enumerable<T>, and First will throw an exception if there are no objects in the Enumerable<T>. Use SingleOrDefault or FirstOrDefault if you want null instead of an exception in those cases.)
As you know there's an extension method called DefaultIfEmpty, based on the documentation:
DefaultIfEmpty:
Returns the elements of the specified sequence or the type parameter's
default value in a singleton collection if the sequence is empty.
So in this case if the sequence is empty, it returns a default value, for example, take a look at this answer:
opencall.Priority = averages.Where(x => x.ProblemCode == opencall.ProblemCode)
.Select(x => x.Priority)
.DefaultIfEmpty("")
.Single();
in this example if the averages is empty, it returns an empty string, But I want to know is there something like an extention method in linq so that if the preperty (x.Priority) is null, returns a default value?
PS: I know we can check that using a if statement:
opencall.Priority = averages.Where(x => x.ProblemCode == opencall.ProblemCode)
.Select(x => x.Priority)
.DefaultIfEmpty("")
.Single();
if (!string.IsNullOrWhiteSpace(opencall.Priority))
opencall.Priority = "Default value";
...
I'm just curious to know that, Is there any kind of extension method for doing that?
You can use the same DefaultOrEmpty method overload to provide the default value. In the above query since we are trying to fetch the Priority property which is of String type. You can provide a default value of String in the method overload:-
opencall.Priority = averages.Where(x => x.ProblemCode == opencall.ProblemCode)
.Select(x => x.Priority)
.DefaultIfEmpty("High")
.Single();
This will result in High for non matching rows.
I'm working with Entity Framework 6 in MVC 5.
I have the following method:
[HttpPost]
public ActionResult UpdateDetails(ApplicationUser applicationUser)
{
var context = new ApplicationDbContext();
var user = context.Users.Select(x => x.UserName == applicationUser.UserName).FirstOrDefault();
//etc etc
}
Users is an IDbSet<ApplicationUser>.
Why am I getting a bool back from the Select method?
My expectation would be to get an ApplicationUser object back. Why isn't this the case?
Thanks
Select() projects an element of a sequence. Since x.UserName == applicationUser.UserName returns a bool, the result of the method will be a boolean.
What you want requires the Where method. This filters the sequence based on the specified predicate:
var user = context.Users.Where(x => x.UserName == applicationUser.UserName).FirstOrDefault();
Which can be shortened to:
var user = context.Users.FirstOrDefault(x => x.UserName == applicationUser.UserName);
This is possible, since this overload of FirstOrDefault() takes a filter predicate as second parameter.
Your select is returning an object that is the result of the comparison.
Change to:
var user = context.Users.FirstOrDefault(x => x.UserName == applicationUser.UserName);
It is because you are SELECTing a boolean.
Since there is no requirement specified, I am guessing your requirement from your attempted code.
use the below line.
var user=context.Users.Where(user=>user.UserName==applicationUser.UserName).FirstOrDefault();
Select literally selects something inside the arguments. So, if you have an expression that returns a bool, Select will return bool.
How can i use "x" variable in if block? I want to return Id field of x if statement is true.
if (UserList.Any(x => x.Type == (int)UserType.SuperUser))
{
return x.Id;
}
You can't access the "LINQ variable" outside the lambda expression.
What you want to do is to get the Id property of any element x that satsify the condition x.Type == (int)UserType.SuperUser.
In this case, replace your Any() by FirstOrDefault().
var item = UserList.FirstOrDefault(x => x.Type == (int)UserType.SuperUser);
if(item != null)
return item.Id;
FirstOrDefault(x => condition on x) return the first element that satsify the condition and null if no element satisfy the condition.
If you want to get the Id value of all elements that satisfy the condition, use the Where and Select extention methods:
return UserList.Where(x => x.Type == (int)UserType.SuperUser).Select(x => x.Id);
Where(x => condition(x)) returns an IEnumerable that contain all elements that satisfy the condition if you prefere to get a "normal" list, add ToList() before ;.
How many matches are you expecting : i.e. how many users in your list do you expect to have the SuperUser type?
If you expect there to be exactly one user that matches (so having zero matching users or more than one matching user would be an error), then use Single:
return UserList.Single(x => x.Type == (int)UserType.SuperUser).Id;
(Note this will throw an exception if there isn't exactly one matching user; alternatively you can use SingleOrDefault and then test for null.)
If you expect there to be one or more and you just want to return the first one:
return UserList.First(x => x.Type == (int)UserType.SuperUser).Id;
(Note this will throw an exception if there isn't exactly one matching user; alternatively you can use FirstOrDefault and then test for null.)
If you expect there to be one or more and you want to return an array of all the Ids of all the matching users:
return UserList.Where(x => x.Type == (int)UserType.SuperUser).Select(u => u.Id).ToArray();
Just to add to the nice answers already posted.
To make the last code sample from Sam Holloways answer look like you are using the x directly you could rewrite that to the SQL-like syntax (don't remember what that is called):
IEnumerable<int> userIds = from x in UserList
where x.Type == UserType.SuperUser
select x.Id;
You can use the count method on userIds to determine if there's anyone satisfying your condition.
Since you are returning the id, and I guess the id is an int and you'll have to return something anyway, and that I guess you would return 0 if it's not there you could use:
return UserList.Where(x => x.Type == UserType.SuperUser).Select(x => x.Id).FirstOrDefault();
With Moq, is it valid to have more than one Matching Argument?
It.Is<string>()
In this example I want the mockMembershipService to return a different ProviderUserKey depending on the User supplied.
mockMembershipService.Setup(
x => x.GetUser(
It.Is<string>(
s => s.Contains("Joe")))
.ProviderUserKey)
.Returns("1234abcd");
mockMembershipService.Setup(
x => x.GetUser(
It.Is<string>(
s => s.Contains("Tracy")))
.ProviderUserKey)
.Returns("5678efgh");
The SetUp defaults to the second statement rather than evaluating each on its own merits.
Isn't it confusing? You are trying to mock GetUser method but you set the Returns for that function's return value's property. You also want to state return type's property based on mocked method.
Here's a way a more clear way:
mockMembershipService.Setup(x => x.GetUser(It.IsAny<string>())
.Returns<string>(GetMembershipUser);
Here's a method to create the membership mock:
private MembershipUser GetMembershipUser(string s)
{
Mock<MembershipUser> user =new Mock<MembershipUser>();
user.Setup(item => item.ProviderUserKey).Returns(GetProperty(s));
return user.Object;
}
Then you write a method for setting that property:
private string GetProperty(string s)
{
if(s.Contains("Joe"))
return "1234abcd";
else if(s.Contains("Tracy"))
return "5678efgh";
}
If you want to restrict input to just "Joe" and "Tracy", you can specify multiple conditions in It.Is<T>(). Something like
mockMembershipService.Setup(x => x.GetUser(It.Is<String>(s => s.Contains("Joe")
|| s.Contains("Tracy")))
.Returns<string>(/* Either Bartosz's or Ufuk's answer */);
Succesive Setup calls nullify previous setups.
You could use your argument in your return callback:
mockMembershipService.Setup(x => x.GetUser(It.IsAny<string>()).ProviderUserKey).Returns<string>(s =>
{
if(s.Contains("Joe"))
return "1234abcd";
else if(s.Contains("Tracy"))
return "5678efgh";
});
If it's important to you to assert the argument passed, you also need It.Is<string>(...) instead of It.IsAny<string>(...).
Please check Introduction to Moq > Matching Arguments documentation:
// matching Func<int>, lazy evaluated
mock.Setup(foo => foo.Add(It.Is<int>(i => i % 2 == 0))).Returns(true);
// matching ranges
mock.Setup(foo => foo.Add(It.IsInRange<int>(0, 10, Range.Inclusive))).Returns(true);
// matching regex
mock.Setup(x => x.DoSomething(It.IsRegex("[a-d]+", RegexOptions.IgnoreCase))).Returns("foo");