i have a class extend from a base class,the base class in another dll.
public class MyMicroBlogCache : RelatedBase<THZUserInfo, MicroBlogCacheModel, int>
and in constructor,inject a ICache
public MyMicroBlogCache(ICache cache,....
in base class ,i use the ICache in a method(for example void A() )
and i write a unit test,mock the ICache
var cache = Substitute.For<ICache>();
cache.PageRelated<THZUserInfo, MicroBlogCacheModel, int>("My", 2217, 0, 3, out all, true)
.Returns(
x =>
{
var list = new List<MicroBlogCacheModel>();
list.Add(new MicroBlogCacheModel { Id = 1, UserId = 2217 });
list.Add(new MicroBlogCacheModel { Id = 1, UserId = 2217 });
list.Add(new MicroBlogCacheModel { Id = 1, UserId = 2217 });
return list;
});
mock with NSubstitute
var cache1 = new Mock<ICache>();
cache1.Setup(ca => ca.PageRelated<THZUserInfo, MicroBlogCacheModel, int>("My", 2217, 0, 3, out all, true))
.Returns(
() =>
{
var list = new List<MicroBlogCacheModel>();
list.Add(new MicroBlogCacheModel { Id = 1, UserId = 2217 });
list.Add(new MicroBlogCacheModel { Id = 1, UserId = 2217 });
list.Add(new MicroBlogCacheModel { Id = 1, UserId = 2217 });
return list;
});
or mock with moq
and the strange thing is:
when i call the method write in base class(RelatedBase),the method(for example A()) call mock ICache,it not return the mock data.
if i override the method in child class(MyMicroBlogCache),and use the same code(override and copy the code from base class),it return the mock data.
if i override,and use base.A(...) ,it not return mock data.
so,when the code in base class,it wrong,and when code in child class,it right.
if i create a class implement ICache,it is ok
both NSubstitute and Moq are same.
i try this with vs2015,vs2013;.net 4.5
why it happens,and how can i fix it
Update:
var cache1 = new Mock<ICache>(MockBehavior.Strict);
cache1.Setup(ca => ca.PageRelated<THZUserInfo, MicroBlogCacheModel, int>("My", 2217, 0, 3, out all, true))
.Returns(
() =>
{
var list = new List<MicroBlogCacheModel>();
list.Add(new MicroBlogCacheModel { Id = 1, UserId = 2217 });
list.Add(new MicroBlogCacheModel { Id = 1, UserId = 2217 });
list.Add(new MicroBlogCacheModel { Id = 1, UserId = 2217 });
return list;
});
then test method call
var r = my.GetRelatedPage(2217, 0, 3, out all, true);
in base class it call
var list = cache.PageRelated<TMainKey, TChild, TMainKey>("My", key, skip, take, out all, desc);
key=2217,skip=0,take=3,desc=true,
You have a generic base class:
RelatedBase<T1, T2, T3>
you also have an inherited class without generic parameters, which specifies the type for each T1, T2, T3.
With genericity, RelatedBase<THZUserInfo, MicroBlogCacheModel, int> is not the same type as RelatedBase<T1, T2, T3>
Now: In your set-up, you explicitly Setup ca.PageRelated<THZUserInfo, MicroBlogCacheModel, int>
If, you call the method on the base class (the generic one) with different argument types, then it will not exactly be the same call as the one which was setup, and therefore, will return the default value for the method.
Try instantiating your Mock with new Mock<ICache>(MockBehavior.MockStrict) and you should have a MockException that confirms that.
Then, think of type arguments as proper arguments : if they don't match, then the setup doesn't apply.
Hope this helps :)
Related
I have following Expression Func which is receiving two input paramters, first is Person Object, second is bool and returning another type of Object PersonProfile
private Exression<Func<Person, bool, PersonProfile>> PersonProfileProjection => (person, isValid) =>
new PersonProfile
{
FirstName = person.FirstName,
HasAddress = isValid ? person.Address1 : null
};
And I am trying to call this while fetching Person table from dbContext.
_dbContext.Persons.Select(PersonProfileProjection);
I am confused how to send boolean parameter inside PersonProfileProjection. It works when I only put one input and one output parameter like this. But I want extra boolean input as well.
Any help would be highly appreciated.
You can follow Microsoft documentation for this : Expression Class
One sample created for SQLite that show above function usage.
public void GetData()
{
var connection = new SQLiteConnection(#"Data Source=database.sqlite;Version=3;");
var context = new DataContext(connection);
connection.Open();
var createtableQuery = #"
drop table Company;
CREATE TABLE[Company]
(
[ID] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
[Seats] INTEGER NOT NULL
);
";
var command = new SQLiteCommand(createtableQuery, connection);
command.ExecuteNonQuery();
Company com = new Company()
{
Id = 6,
Seats = 7
};
context.GetTable<Company>().InsertOnSubmit(com);
context.SubmitChanges();
var companies = context.GetTable<Company>();
foreach (var company in companies)
{
Console.WriteLine("Company: {0} {1}",
company.Id, company.Seats);
}
//compile Expression using Compile method to invoke it as Delegate
Func<int,int, Company> PersonProfileProjectionComp = PersonProfileProjection.Compile();
var dd = companies.Select(p => PersonProfileProjectionComp(p.Id,p.Seats));
//// Below line inline use. Both works.
//var dd = companies.Select(p => PersonProfileProjection.Compile().Invoke(p.Id,p.Seats));
}
private System.Linq.Expressions.Expression<Func<int, int, Company>> PersonProfileProjection => (person, seats) =>
new Company
{
Id = person,
Seats = seats
};
or in one line use this :
PersonProfileProjection.Compile().Invoke(person, isValid)
You could declare it as a Func instead of an expression:
private Func<Person, bool, PersonProfile> PersonProfileProjection => (person, isValid) =>
new PersonProfile
{
FirstName = person.FirstName,
HasAddress = isValid // do what you meant to do
};
... and call it as:
_dbContext.Persons.Select(p => PersonProfileProjection(p, true));
You could as well write an ordinary method:
private PersonProfile PersonProfileProjection(Person person, bool isValid)
{
return new PersonProfile
{
FirstName = person.FirstName,
HasAddress = isValid // do what you want to do
};
}
...and call it the same way:
_dbContext.Persons.Select(p => PersonProfileProjection(p, true));
Final rephrase
Below I join two sequences and I wondered if it would be faster to create a Dictionary of one sequence with the keySelector of the join as key and iterate through the other collection and find the key in the dictionary.
This only works if the key selector is unique. A real join has no problem with two records having the same key. In a dictionary you'll have to have unique keys
I measured the difference, and I noticed that the dictionary method is about 13% faster. In most use cases ignorable. See my answer to this question
Rephrased question
Some suggested that this question is the same question as LINQ - Using where or join - Performance difference?, but this one is not about using where or join, but about using a Dictionary to perform the join.
My question is: if I want to join two sequences based on a key selector, which method would be faster?
Put all items of one sequence in a Dictionary and enumerate the other sequence to see if the item is in the Dictionary. This would mean to iterate through both sequences once and calculate hash codes on the keySelector for every item in both sequences once.
The other method: use System.Enumerable.Join.
The question is: Would Enumerable.Join for each element in the first list iterate through the elements in the second list to find a match according to the key selector, having to compare N * N elements (is this called second order?) or would it use a more advanced method?
Original question with examples
I have two classes, both with a property Reference. I have two sequences of these classes and I want to join them based on equal Reference.
Class ClassA
{
public string Reference {get;}
...
}
public ClassB
{
public string Reference {get;}
...
}
var listA = new List<ClassA>()
{
new ClassA() {Reference = 1, ...},
new ClassA() {Reference = 2, ...},
new ClassA() {Reference = 3, ...},
new ClassA() {Reference = 4, ...},
}
var listB = new List<ClassB>()
{
new ClassB() {Reference = 1, ...},
new ClassB() {Reference = 3, ...},
new ClassB() {Reference = 5, ...},
new ClassB() {Reference = 7, ...},
}
After the join I want combinations of ClassA objects and ClassB objects that have an equal Reference. This is quite simple to do:
var myJoin = listA.Join(listB, // join listA and listB
a => a.Reference, // from listA take Reference
b => b.Reference, // from listB take Reference
(objectA, objectB) => // if references equal
new {A = objectA, B = objectB}); // return combination
I'm not sure how this works, but I can imagine that for each a in listA the listB is iterated to see if there is a b in listB with the same reference as A.
Question: if I know that the references are Distinct wouldn't it be more efficient to convert B into a Dictionary and compare the Reference for each element in listA:
var dictB = listB.ToDictionary<string, ClassB>()
var myJoin = listA
.Where(a => dictB.ContainsKey(a.Reference))
.Select(a => new (A = a, B = dictB[a.Reference]);
This way, every element of listB has to be accessed once to put in the dictionary and every element of listA has to be accessed once, and the hascode of Reference has to be calculated once.
Would this method be faster for large collections?
I created a test program for this and measured the time it took.
Suppose I have a class of Person, each person has a name and a Father property which is of type Person. If the Father is not know, the Father property is null
I have a sequence of Bastards (no father) that have exactly one Son and One Daughter. All Daughters are put in one sequence. All sons are put in another sequences.
The query: join the sons and the daughters that have the same father.
Results: Joining 1 million families using Enumerable.Join took 1.169 sec. Joining them using Dictionary join used 1.024 sec. Ever so slightly faster.
The code:
class Person : IEquatable<Person>
{
public string Name { get; set; }
public Person Father { get; set; }
// + a lot of equality functions get hash code etc
// for those interested: see the bottom
}
const int nrOfBastards = 1000000; // one million
var bastards = Enumerable.Range (0, nrOfBastards)
.Select(i => new Person()
{ Name = 'B' + i.ToString(), Father = null })
.ToList();
var sons = bastards.Select(father => new Person()
{Name = "Son of " + father.Name, Father = father})
.ToList();
var daughters = bastards.Select(father => new Person()
{Name = "Daughter of " + father.Name, Father = father})
.ToList();
// join on same parent: Traditionally and using Dictionary
var stopwatch = Stopwatch.StartNew();
this.TraditionalJoin(sons, daughters);
var time = stopwatch.Elapsed;
Console.WriteLine("Traditional join of {0} sons and daughters took {1:F3} sec", nrOfBastards, time.TotalSeconds);
stopwatch.Restart();
this.DictionaryJoin(sons, daughters);
time = stopwatch.Elapsed;
Console.WriteLine("Dictionary join of {0} sons and daughters took {1:F3} sec", nrOfBastards, time.TotalSeconds);
}
private void TraditionalJoin(IEnumerable<Person> boys, IEnumerable<Person> girls)
{ // join on same parent
var family = boys
.Join(girls,
boy => boy.Father,
girl => girl.Father,
(boy, girl) => new { Son = boy.Name, Daughter = girl.Name })
.ToList();
}
private void DictionaryJoin(IEnumerable<Person> sons, IEnumerable<Person> daughters)
{
var sonsDictionary = sons.ToDictionary(son => son.Father);
var family = daughters
.Where(daughter => sonsDictionary.ContainsKey(daughter.Father))
.Select(daughter => new { Son = sonsDictionary[daughter.Father], Daughter = daughter })
.ToList();
}
For those interested in the equality of Persons, needed for a proper dictionary:
class Person : IEquatable<Person>
{
public string Name { get; set; }
public Person Father { get; set; }
public bool Equals(Person other)
{
if (other == null)
return false;
else if (Object.ReferenceEquals(this, other))
return true;
else if (this.GetType() != other.GetType())
return false;
else
return String.Equals(this.Name, other.Name, StringComparison.OrdinalIgnoreCase);
}
public override bool Equals(object obj)
{
return this.Equals(obj as Person);
}
public override int GetHashCode()
{
const int prime1 = 899811277;
const int prime2 = 472883293;
int hash = prime1;
unchecked
{
hash = hash * prime2 + this.Name.GetHashCode();
if (this.Father != null)
{
hash = hash * prime2 + this.Father.GetHashCode();
}
}
return hash;
}
public override string ToString()
{
return this.Name;
}
public static bool operator==(Person x, Person y)
{
if (Object.ReferenceEquals(x, null))
return Object.ReferenceEquals(y, null);
else
return x.Equals(y);
}
public static bool operator!=(Person x, Person y)
{
return !(x==y);
}
}
I am trying to unit test a webapi project with zero joy.
The api is using EF6.1 to access data. My test project is using moq and xunit.
I have setup a basic test like
[Fact]
public void CheckGroupedDataCountEquals2()
{
var mockData = new List<Skill>()
{
new Skill() {Id = 1, Name = ".net"},
new Skill() {Id = 2, Name = "asp.net", ParentId = 1},
new Skill() {Id = 3, Name = "c#", ParentId = 1},
new Skill() {Id = 4, Name = "php"},
new Skill() {Id = 5, Name = "zend", ParentId = 4},
new Skill() {Id = 6, Name = "zend3", ParentId = 5}
};
// Arrange
_skillMock.Setup(x => x.GroupedSkills())
.Returns((new List<GroupedSkill>()));
var controller = new SkillsController(_skillMock.Object);
// Act
IHttpActionResult actionResult = controller.Get();
var contentResult = actionResult as OkNegotiatedContentResult<List<GroupedSkill>>;
// Assert
Assert.NotNull(contentResult);
var result = contentResult.Content as List<GroupedSkill>;
Assert.Equal(2,result.Count);
}
My apicontroller action looks like
[HttpGet]
[Route("")]
// GET api/<controller>
public IHttpActionResult Get()
{
var data = _skillRepository.GroupedSkills();
if (data!=null)
{
return Ok(data);
}
return NotFound();
}
And finally....my repo
public List<GroupedSkill> GroupedSkills()
{
using (var context = new DataContext())
{
var data = context.Skills.ToList();
var newList = data.Where(x => x.ParentId != null).ToList().GroupBy(x => x.ParentId,
(key, elements) =>
new
{
data.First(i => i.Id == key).Name,
GroupId = key,
Skills = elements.ToList()
})
.ToList();
var filtered = new List<GroupedSkill>();
foreach (var item in newList)
{
filtered.Add(new GroupedSkill()
{
GroupId = item.GroupId.Value,
Name = item.Name,
Skills = item.Skills
});
}
return filtered;
}
}
My test is always failing with the group count is always 0. I think its because I am not adding my mock list of mockData and my repository knows nothing about it.....am I right? how do I pass my mock list of data to the repo from my test
You are correct, you're passing it an empty list.
You first create the mockedData list, and populate it with real Skills, but it doesn't look like you ever use it. This should also be considered part of the Arrange section, for what that's worth.
var mockData = new List<Skill>()
{
new Skill() {Id = 1, Name = ".net"},
new Skill() {Id = 2, Name = "asp.net", ParentId = 1},
new Skill() {Id = 3, Name = "c#", ParentId = 1},
new Skill() {Id = 4, Name = "php"},
new Skill() {Id = 5, Name = "zend", ParentId = 4},
new Skill() {Id = 6, Name = "zend3", ParentId = 5}
};
Then when you begin your Arrange section by creating the _skillMock, but you creating a new, empty list.
// Arrange
_skillMock.Setup(x => x.GroupedSkills())
.Returns((new List<GroupedSkill>()));
And I can't tell where _skillMock is initialized; you shouldn't need it (and really don't want it) to be a class instance variable, because it could change across other tests. Instead, you should be setting this list up similar to how you built your mockData list.
You are properly passing the mock object in this line:
var controller = new SkillsController(_skillMock.Object);
However because you haven't added anything to that list, the list will always be empty.
Ideally, what I think you want is a real list filled with mocks of your GroupedSkill objects, something like this:
var mockData = new List<GroupedSkill>()
{
new Mock<GroupedSkill>(1, ".net").Object,
new Mock<GroupedSkill>(2, "asp.net", 1).Object,
// ... keep going
}
And then pass that list to your controller instead.
.NET 4, I have
public class Humi
{
public int huKey { get; set; }
public string huVal { get; set; }
}
And in another class is this code in a method:
IEnumerable<Humi> someHumi = new List<Humi>(); //This is actually ISingleResult that comes from a LinqToSql-fronted sproc but I don't think is relevant for my question
var humia = new Humi { huKey = 1 , huVal = "a"};
var humib = new Humi { huKey = 1 , huVal = "b" };
var humic = new Humi { huKey = 2 , huVal = "c" };
var humid = new Humi { huKey = 2 , huVal = "d" };
I want to create a single IDictionary <int,string[]>
with key 1 containing ["a","b"] and key 2 containing ["c","d"]
Can anyone point out a decent way to to that conversion with Linq?
Thanks.
var myDict = someHumi
.GroupBy(h => h.huKey)
.ToDictionary(
g => g.Key,
g => g.ToArray())
Create an IEnumerable<IGrouping<int, Humi>> and then project that into a dictionary. Note .ToDictionary returns a Dictionary, not an IDictionary.
You can use ToLookup() which allows each key to hold multiple values, exactly your scenario (note that each key would hold an IEnumerable<string> of values though not an array):
var myLookup = someHumi.ToLookup(x => x.huKey, x => x.huVal);
foreach (var item in myLookup)
{
Console.WriteLine("{0} contains: {1}", item.Key, string.Join(",", item));
}
Output:
1 contains: a,b
2 contains: c,d
Assume I have generic list L of some type in c#. Then, using linq, call OrderBy() on it, passing in a lambda expression.
If I then re-assign the L, the previous order operation will obviously be lost.
Is there any way I can 'save' the lambda expression I used on the list before i reassigned it, and re-apply it?
Use a Func delegate to store your ordering then pass that to the OrderBy method:
Func<int, int> orderFunc = i => i; // func for ordering
var list = Enumerable.Range(1,10).OrderByDescending(i => i); // 10, 9 ... 1
var newList = list.OrderBy(orderFunc); // 1, 2 ... 10
As another example consider a Person class:
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
Now you want to preserve a sort order that sorts by the Name property. In this case the Func operates on a Person type (T) and the TResult will be a string since Name is a string and is what you are sorting by.
Func<Person, string> nameOrder = p => p.Name;
var list = new List<Person>
{
new Person { Id = 1, Name = "ABC" },
new Person { Id = 2, Name = "DEF" },
new Person { Id = 3, Name = "GHI" },
};
// descending order by name
foreach (var p in list.OrderByDescending(nameOrder))
Console.WriteLine(p.Id + ":" + p.Name);
// 3:GHI
// 2:DEF
// 1:ABC
// re-assinging the list
list = new List<Person>
{
new Person { Id = 23, Name = "Foo" },
new Person { Id = 14, Name = "Buzz" },
new Person { Id = 50, Name = "Bar" },
};
// reusing the order function (ascending by name in this case)
foreach (var p in list.OrderBy(nameOrder))
Console.WriteLine(p.Id + ":" + p.Name);
// 50:Bar
// 14:Buzz
// 23:Foo
EDIT: be sure to add ToList() after the OrderBy calls if you need a List<T> since the LINQ methods will return an IEnumerable<T>.
Calling ToList() or ToArray() on your IEnumerable<T> will cause it to be immediately evaluated. You can then assign the resulting list or array to "save" your ordered list.