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.
Related
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 :)
I have a list of object like
List
category has properties, CategoryId, CategoryName, Categorymessage,
I have to use this list to update records in the database table
Categories, which has the same columns CategoryId, CategoryName, CategoryMessage
for the items in list which have a matching CategoryId as in the database table
How can I do that as a bulk update, using Entity framework extensions,
the examples I saw have the update value hard coded like below, (statusId =2),
whereas for me that value has to be retrieved from the item in the list which matches the categoryId in the database table.
context.Tasks.Update(
t => t.StatusId == 1,
t => new Task {StatusId = 2});
Thanks in advance.
I am not sure whether this what you are looking for? I haven't run this code.
List<Category> categoryList = new List<Category> {
new Category { Id = 1, Message = "A", Name = "A"},
new Category { Id = 2, Message = "B", Name = "B"},
new Category { Id = 3, Message = "C", Name = "C"},
new Category { Id = 4, Message = "D", Name = "D"},
};
using (var container = new Model1Container())
{
IQueryable<Category> categoryQueryable = container.Categories.Where(x => categoryList.Any(t => t.Id == x.Id));
foreach (Category item in categoryQueryable)
{
var categorySource = categoryList.Where(x => x.Id == item.Id).Select(m => m).FirstOrDefault();
item.Message = categorySource.Message;
item.Name = categorySource.Message;
}
container.SaveChanges();
}
I want to group by category, show it's name, then show the highest id that is related to it. Here's some data and the result that I want further down. Any ideas? I've been playing around with GroupJoin but can't seem to get it to work.
My Data
var stuff = new[] {
new {id = 5, catId = 2},
new {id = 56, catId = 2},
new {id = 56, catId = 2},
new {id = 8, catId = 1},
new {id = 9, catId = 3}};
var categories = new[] {
new {catId = 1, Name = "Water"},
new {catId = 4, Name = "Wind"},
new {catId = 2, Name = "Fire"}};
What I want my results to look like
Water - 8
Wind - null
Fire - 56
categories
.GroupJoin
(
stuff,
c=>c.catId,
s=>s.catId,
(c,s)=>new
{
c.Name,
Max = s.Any() ? (int?)s.Max (m => m.id) : null
}
);
It seems that you want a "LEFT OUTER JOIN" with LINQ:
var query = from cat in categories
join s in stuff
on cat.catId equals s.catId into gj
from stuffJoin in gj.DefaultIfEmpty()
group stuffJoin by new { cat.catId, cat.Name } into catGroup
select new {
Category = catGroup.Key.Name,
MaxID = catGroup.Max(s => s == null ? 0 : s.id) // stuff is null for Wind
};
foreach (var x in query)
Console.WriteLine("Category: {0} Max-ID: {1}", x.Category, x.MaxID);
Outputs:
Category: Water Max-ID: 8
Category: Wind Max-ID: 0
Category: Fire Max-ID: 56
I am using Dynamic Linq helper for grouping data. My code is as follows :
Employee[] empList = new Employee[6];
empList[0] = new Employee() { Name = "CA", State = "A", Department = "xyz" };
empList[1] = new Employee() { Name = "ZP", State = "B", Department = "xyz" };
empList[2] = new Employee() { Name = "AC", State = "B", Department = "xyz" };
empList[3] = new Employee() { Name = "AA", State = "A", Department = "xyz" };
empList[4] = new Employee() { Name = "A2", State = "A", Department = "pqr" };
empList[5] = new Employee() { Name = "BA", State = "B", Department = "pqr" };
var empqueryable = empList.AsQueryable();
var dynamiclinqquery = DynamicQueryable.GroupBy(empqueryable, "new (State, Department)", "it");
How can I get back the Key and corresponding list of grouped items i.e IEnumerable of {Key, List} from dynamiclinqquery ?
I solved the problem by defining a selector that projects the Key as well as Employees List.
var eq = empqueryable.GroupBy("new (State, Department)", "it").Select("new(it.Key as Key, it as Employees)");
var keyEmplist = (from dynamic dat in eq select dat).ToList();
foreach (var group in keyEmplist)
{
var key = group.Key;
var elist = group.Employees;
foreach (var emp in elist)
{
}
}
The GroupBy method should still return something that implements IEnumerable<IGrouping<TKey, TElement>>.
While you might not be able to actually cast it (I'm assuming it's dynamic), you can certainly still make calls on it, like so:
foreach (var group in dynamiclinqquery)
{
// Print out the key.
Console.WriteLine("Key: {0}", group.Key);
// Write the items.
foreach (var item in group)
{
Console.WriteLine("Item: {0}", item);
}
}
Is is possible to sort an item in a IEnumerable list using LINQ?
For example:
IEnumerable<sample> sam = new List<sample>()
{
new sample{ id = 1, name = "sample 1", list = new List<int>{5,6,1}},
new sample{ id = 2, name = "sample 1", list = new List<int>{2,9}},
new sample{ id = 3, name = "sample 1", list = new List<int>{8,3,7}},
new sample{ id = 4, name = "sample 1", list = new List<int>{8,4,3}},
new sample{ id = 5, name = "sample 1", list = new List<int>{5,1,7}},
new sample{ id = 6, name = "sample 1", list = new List<int>{6,9,7}}
};
The expected output from the sample given above would be the sorted values in List.
Expected output is:
sample{ id = 1, name = "sample 1", list = new List<int>{1,5,6}},
sample{ id = 2, name = "sample 1", list = new List<int>{2,9}},
sample{ id = 3, name = "sample 1", list = new List<int>{3,7,8},
sample{ id = 4, name = "sample 1", list = new List<int>{3,4,8}},
sample{ id = 5, name = "sample 1", list = new List<int>{1,5,7}},
sample{ id = 6, name = "sample 1", list = new List<int>{6,7,9}}
thanks
Try,
sam.All(p => { p.list.Sort(); return true; });
((List<sample>)sam).ForEach(s => s.list.Sort());
The general shape for LINQ is that it does not change the original data. For example, if we have a list
var ints = new List<int>{5,6,1};
and use linq to 'sort it'
var sorted = ints.OrderBy();
we end up with two lists
ints => { 5,6,1}
sorted => {1,5,6}
In your above example, it depends on what you want the output to be
If you want a new list of samples where the list is sorted then you can use
var newSampleList = samples.Select( sam => new Sample {
id = sam.id,
name = sam.name,
list = new List<int>(sam.list.OrderBy())
});
If you do not want to create a new list but want to sort the values in place it is not really what LINQ is intended for but it can be done using something like AVD's answer to execute functionality on each member (in this case call Sort on the list).
NOTE: This will only work if sample.list is defined as a List() as Sort() only exists on List<>. If defined as IList or IEnumerable it will not work.