NUnit DataSource from a different class - c#

I am trying to make a test project using N Unit. I have everything working and now but i was wondering if it is possible to split the test cases into a completely separate class or would the only feasible way would be to push the data to a file or a partial class? basically I would like the data in a separate file instead of having all the data and the tests in one file. Or maybe that more of the standard and create different classes for each rule test.
[Test, TestCaseSource("TenantsRules")]
public void CheckDNQTenantsRules(DNQTenantData testData)
{
CoreServicesBroker.DNQCoreServiceBroker broker = new CoreServicesBroker.DNQCoreServiceBroker();
string actualDNQReason = string.Empty;
int actualReturnCode = broker.CheckDNQTenants(testData.FormCode, testData.StateCode, testData.EffectiveDate, testData.NumberOfTenants, ref actualDNQReason);
Assert.AreEqual(testData.ExpectedDNQReturnCode, actualReturnCode);
Assert.AreEqual(testData.ExpectedDNQReason, actualDNQReason);
}
public static IEnumerable<DNQTenantData> TenantsRules()
{
yield return new DNQTenantData() { FormCode = 9, StateCode = "OH", EffectiveDate = DateTime.Now, NumberOfTenants = 7, ExpectedDNQReturnCode = 1, ExpectedDNQReason = "Number of Tenants exceeded." };
yield return new DNQTenantData() { FormCode = 9, StateCode = "OH", EffectiveDate = DateTime.Now, NumberOfTenants = 5, ExpectedDNQReturnCode = 0, ExpectedDNQReason = "" };
}

I believe NUnits TestCaseData will solve your problem:
[TestFixture]
public class YourTest
{
[Test, TestCaseSource(typeof(YourTestCaseProvider), nameof(YourTestCaseProvider.TenantsRules)]
public void CheckDNQTenantsRules(DNQTenantData testData)
{
CoreServicesBroker.DNQCoreServiceBroker broker = new CoreServicesBroker.DNQCoreServiceBroker();
string actualDNQReason = string.Empty;
int actualReturnCode = broker.CheckDNQTenants(testData.FormCode, testData.StateCode, testData.EffectiveDate, testData.NumberOfTenants, ref actualDNQReason);
Assert.AreEqual(testData.ExpectedDNQReturnCode, actualReturnCode);
Assert.AreEqual(testData.ExpectedDNQReason, actualDNQReason);
}
}
public class YourTestCaseProvider
{
public static IEnumerable TenantsRules()
{
yield return new TestCaseData(new DNQTenantData() { FormCode = 9, StateCode = "OH", EffectiveDate = DateTime.Now, NumberOfTenants = 7, ExpectedDNQReturnCode = 1, ExpectedDNQReason = "Number of Tenants exceeded." })
yield return new TestCaseData(new DNQTenantData() { FormCode = 9, StateCode = "OH", EffectiveDate = DateTime.Now, NumberOfTenants = 5, ExpectedDNQReturnCode = 0, ExpectedDNQReason = "" });
}
}

Related

Sorting list with rules in C#

Tell me if there is a way to sort the list by the rules.
I have several playing decks and each has its own rules:
Count - how many cards to take from the deck
From / Before - in which interval the cards should be (If 0, then in any)
Row - how many cards can fall out in a row
My current code:
private void ShuffleDecks()
{
List<TestCard> testCards = new();
TestDesk desk1 = new TestDesk
{
From = 0,
Before = 0,
Row = 2,
Count = 3
};
desk1.Cards = new List<TestCard>
{
new("a1", desk1),
new("a2", desk1),
new("a3", desk1),
};
TestDesk desk2 = new TestDesk
{
From = 1,
Before = 4,
Row = 1,
Count = 2
};
desk2.Cards = new List<TestCard>
{
new("b1", desk2),
new("b2", desk2),
new("b3", desk2),
};
TestDesk desk3 = new TestDesk
{
From = 3,
Before = 5,
Row = 0,
Count = 2
};
desk3.Cards = new List<TestCard>
{
new("c1", desk3),
new("c2", desk3),
new("c3", desk3),
};
List<TestDesk> desks = new List<TestDesk> { desk1, desk2, desk3 };
foreach (TestDesk desk in desks)
{
desk.Cards.Shuffle();
testCards.AddRange(desk.Cards.Take(desk.Count).ToList());
}
testCards.Sort();
Debug.LogWarning($"{string.Join(", ", testCards.Select(x => x.Name))}");
}
TestDesk and TestCard:
public class TestDesk
{
public List<TestCard> Cards;
public int From;
public int Before;
public int Row;
public int Count;
}
public class TestCard
{
public string Name;
public TestDesk Desk;
public TestCard(string name, TestDesk desk)
{
Name = name;
Desk = desk;
}
}

How to save sub-document/sub-collection with C# MongoDb.Driver

I'm using MongoDb.Driver in C# to save information to my backend.
I've created a simple Repository to store a generic object:
public abstract class MongoRepository<TDocument> : IRepository<TDocument>
where TDocument : Entity
{
#region Private Fields
private readonly IMongoCollection<TDocument> _collection;
#endregion
#region Protected Properties
protected abstract String CollectionName { get; }
#endregion
#region Constructors
public MongoRepository(IMongoDbSettings settings)
{
IMongoDatabase? database = new MongoClient(settings.ConnectionString).GetDatabase("default");
_collection = database.GetCollection<TDocument>(CollectionName);
}
#endregion
#region Public Methods
public IQueryable<TDocument> AsQueryable()
{
return _collection.AsQueryable();
}
public IEnumerable<TDocument> FilterBy(
Expression<Func<TDocument, bool>> filterExpression)
{
return _collection.Find(filterExpression).ToEnumerable();
}
public IEnumerable<TProjected> FilterBy<TProjected>(
Expression<Func<TDocument, bool>> filterExpression,
Expression<Func<TDocument, TProjected>> projectionExpression)
{
return _collection.Find(filterExpression).Project(projectionExpression).ToEnumerable();
}
public async Task<TDocument> FindOne(Expression<Func<TDocument, bool>> filterExpression)
{
return await _collection.Find(filterExpression).FirstOrDefaultAsync();
}
public async Task<IEnumerable<TDocument>> Get()
{
IAsyncCursor<TDocument>? asyncCursor = await _collection.FindAsync(_ => true);
return await asyncCursor.ToListAsync();
}
public async Task<TDocument> Get(Guid id)
{
FilterDefinition<TDocument>? filter = Builders<TDocument>.Filter.Eq(doc => doc.Id, id);
return await _collection.Find(filter).SingleOrDefaultAsync();
}
public async Task Create(TDocument document)
{
await _collection.InsertOneAsync(document);
}
public async Task CreateMany(ICollection<TDocument> documents)
{
await _collection.InsertManyAsync(documents);
}
public async Task Update(TDocument document)
{
FilterDefinition<TDocument>? filter = Builders<TDocument>.Filter.Eq(doc => doc.Id, document.Id);
await _collection.FindOneAndReplaceAsync(filter, document);
}
public async Task Delete(Expression<Func<TDocument, bool>> filterExpression)
{
await _collection.DeleteManyAsync(filterExpression);
}
public async Task Delete(Guid id)
{
FilterDefinition<TDocument>? filter = Builders<TDocument>.Filter.Eq(doc => doc.Id, id);
await _collection.FindOneAndDeleteAsync(filter);
}
public async Task Delete(TDocument element)
{
await Delete(element.Id);
}
#endregion
}
Up until now it was working fine, but I first encounter the case of saving an object that has sub-objects and collections:
public class Dashboard : Entity//Entity has just a public Guid Id {get;set;}
{
public Guid OrganizationLevelId { get; set; }
public string Name { get; set; }
public bool IsShared { get; set; }
public Guid? OwnerId { get; set; }
public List<Widget> Widgets { get; } = new();
}
And now, when I'm trying to save a document that has a collection, the array of widgets isn't saved:
await _dashboardsRepository.Create(new Dashboard()
{
Name = "Default Dashboard",
IsShared = true,
Id = Guid.NewGuid(),
OrganizationLevelId = rootLevel.Id,
Widgets =
{
new Widget() {Columns = 2, Rows = 1, Y = 0, X = 0, Title = "Component 1"},
new Widget() {Columns = 1, Rows = 1, Y = 1, X = 0, Title = "Comp 2"},
new Widget() {Columns = 1, Rows = 1, Y = 1, X = 1, Title = "Comp 3"},
new Widget() {Columns = 2, Rows = 2, Y = 0, X = 1, Title = "Max 2x2", MaxItemsColumns = 2, MaxItemsRows = 2},
new Widget() {Columns = 2, Rows = 3, Y = 0, X = 4, Title = "Min 2x2", MinItemColumns = 2, MinItemsRows = 2},
new Widget() {Columns = 4, Rows = 2, Y = 2, X = 0, Title = "Component 6"},
new Widget() {Columns = 2, Rows = 2, Y = 3, X = 4, Title = "Component 7"}
}
}
)
I'm trying to keep some kind of separation of concern, so my business objects doesn't reference MongoDb.
I guess there is something to indicate that I want the child properties to be persisted but I can't find how, any idea?
I've resolved the issue. In fact there was no additional "serialization" required, but I did 2 changes:
My "Widgets" property was a
public List<Widget> Widgets{get;} = new List<Widget>()
After I transformed it to
public List<Widget> Widgets{get;set;}(and initialize the collection when creating a dashboard)
it works.
I'm not sure if it's because of the missing setter or the default initialization of the collection, but it works now.

Filtering mongodb data collection filter

I used mongodb in my backend to store some customer personal information and I need to fetch the user who ages 30, 32 and 35.
I tried below ways to get but it returns zero results and I used C# MongoDB.Driver
C# code
Age = new string[] { "26-30", "31-35" }
DateTime today = DateTime.Today;
var filter = Builders<Customer>.Filter.Empty;
foreach (var item in searchFilterBlock.Age)
{
var ageBetween = item.Split('-');
int.TryParse(ageBetween[0], out int startYear);
int.TryParse(ageBetween[1], out int endYear);
var start = today.AddYears(-startYear);
var end = today.AddYears(-endYear);
filter = filter & (Builders<Customer>.Filter.Gte(x => x.Dob, start)
& Builders<Customer>.Filter.Lte(x=>x.Dob, end));
}
// to execute the filter
var searchResult = _context.Customer.Find(filter).ToList(); // it return 0 result
Need to get who has ages 30, 32 and 35.
you can get customers who are aged 30,32 and 35 by using an $or filter like the following:
db.Customer.find({
"$or": [
{
"DOB": {
"$lte": ISODate("1989-06-22T14:57:50.168Z"),
"$gte": ISODate("1988-06-22T14:57:50.168Z")
}
},
{
"DOB": {
"$lte": ISODate("1987-06-22T14:57:50.168Z"),
"$gte": ISODate("1986-06-22T14:57:50.168Z")
}
},
{
"DOB": {
"$lte": ISODate("1984-06-22T14:57:50.168Z"),
"$gte": ISODate("1983-06-22T14:57:50.168Z")
}
}
]
})
here's the c# code that generated the above find query using the convenience library MongoDB.Entities [disclaimer: i'm the author]
using MongoDB.Driver;
using MongoDB.Entities;
using System;
using System.Collections.Generic;
namespace StackOverflow
{
public class Program
{
public class Customer : Entity
{
public string Name { get; set; }
public DateTime DOB { get; set; }
}
private static void Main(string[] args)
{
new DB("test");
(new[] {
new Customer{ Name = "I am 29", DOB = DateTime.UtcNow.AddYears(-29)},
new Customer{ Name = "I am 30", DOB = DateTime.UtcNow.AddYears(-30)},
new Customer{ Name = "I am 32", DOB = DateTime.UtcNow.AddYears(-32)},
new Customer{ Name = "I am 35", DOB = DateTime.UtcNow.AddYears(-35)},
new Customer{ Name = "I am 36", DOB = DateTime.UtcNow.AddYears(-36)}
}).Save();
var ages = new[] { 30, 32, 35 };
var filters = new List<FilterDefinition<Customer>>();
foreach (var age in ages)
{
var start = DateTime.UtcNow.AddYears(-age);
var end = DateTime.UtcNow.AddYears(-age - 1);
filters.Add(DB.Filter<Customer>()
.Where(c => c.DOB <= start && c.DOB >= end));
}
var customers = DB.Find<Customer>()
.Many(f => f.Or(filters))
.ToArray();
}
}
}

Some loop with conditions. Specific problem

I have a small problem with mathematics or combinatorics in my C# code. I don't know how to write this easiest.
I have a class Section and TestClass but not a method to return expected result.
public class Section
{
public int Id { get; set; }
public int Pages { get; set; }
public string Name { get; set; }
}
[TestFixture]
public class PermutatorTest
{
private IList<Section> _sections;
private int _targetPage;
[SetUp]
public void SetUp()
{
_targetPage = 30;
_sections = new List<Section>
{
new Section {Id = 1, Pages = 15, Name = "A"},
new Section {Id = 2, Pages = 15, Name = "B"},
new Section {Id = 3, Pages = 10, Name = "C" },
new Section {Id = 4, Pages = 10, Name = "D"},
new Section {Id = 5, Pages = 10, Name = "E"},
new Section {Id = 6, Pages = 5, Name = "F"}
};
}
[Test]
public void GetPermutationsTest()
{
// Code to return list of all combinations
}
}
I want to get each combination which give me 30 as a sum of Pages.
it could be return as a string based on name or Id e.g AA or 11 , AB or 12
Of course, the order is not important ( AB and BA is the same... CCD and CDC and DCC too )
Final result should look like this: (30 correct results)
AA
AB
ACF
ADF
AEF
AFFF
BB
BCF
BDF
BEF
BFFF
CCC
CCD
CCE
CDD
CEE
CDE
CFFFF
CDFF
CCFF
CEFF
DDFF
DEFF
DFFFF
DDD
DDE
EFFFF
EEE
EEFF
FFFFFF
e.g. DDE = 10+10+10 = 30 OK
CFFFF = 10 + 5 +5 +5 +5 = 30 Ok
etc.
I dont have idea for best way to create loops for this, and put records to List
Thank you very much for every attempt to help me.
This was my original idea I was going to post for you, it just returned a list of strings
public List<String> result;
public void GetResultList(int startOffs, String CurNames, int curTotal)
{
for (int newOffs = startOffs; newOffs < _sections.Count; newOffs++)
{
int newTotal = curTotal + _sections[newOffs].Pages;
String newNames = CurNames+ _sections[newOffs].Name;
if (newTotal < _targetPage)
GetResultList(newOffs, newNames, newTotal);
else if (newTotal == _targetPage)
result.Add(newNames);
}
}
called by initialising the result & start parameters :
result = new List<String>();
GetResultList(0,"",0);
This is a version modified to use your Config class
public void GetResultList(int startOffs, Config CurConfig)
{
for (int newOffs = startOffs; newOffs < _sections.Count; newOffs++)
{
Config newConfig = new Config{ Name = CurConfig.Name + _sections[newOffs].Name,
Ids = CurConfig.Ids + _sections[newOffs].Id.ToString(),
Pages = CurConfig.Pages + _sections[newOffs].Pages};
if (newConfig.Pages < _targetPage)
GetResultList(newOffs, newConfig);
else if (newConfig.Pages == _targetPage)
_result.Add(newConfig);
}
}
calling needs the result initialising & a starting Config instance
_result = new List<Config>();
Config s = new Config { Ids = "", Pages=0, Name=""};
GetResultList(0,s);
Only for Information and Searchers.
I know, this code is not so clean
but I put it here as a nUnit Test...
it returns what I wanted ... i think.
using System;
using System.Collections.Generic;
using NUnit.Framework;
[TestFixture]
public class PermutatorTest
{
private IList<Section> _sections;
private int _targetPage;
private IList<Config> _result;
[SetUp]
public void SetUp()
{
_targetPage = 30;
_sections = new List<Section>
{
new Section {Id = 1, Pages = 15, Name = "A"},
new Section {Id = 2, Pages = 15, Name = "B"},
new Section {Id = 3, Pages = 10, Name = "C" },
new Section {Id = 4, Pages = 10, Name = "D"},
new Section {Id = 5, Pages = 10, Name = "E"},
new Section {Id = 6, Pages = 5, Name = "F"}
};
_result = new List<Config>();
}
[Test]
public void GetPermutationsTest()
{
for (var b =0 ; b<=_sections.Count-1; b++)
{
var config = new Config
{
Name = _sections[b].Name,
Ids = _sections[b].Id.ToString(),
Pages = _sections[b].Pages
};
GoDeeperAndAddToResult(config, b);
}
Console.WriteLine(_result.Count);
foreach (var item in _result)
{
Console.WriteLine($"{item.Name} - {item.Ids} - {item.Pages}");
}
}
private void GoDeeperAndAddToResult(Config config, int startIndex)
{
for (var b = startIndex; b <= _sections.Count-1; b++)
{
var section = _sections[b];
var combName = config.Name;
var combIds = config.Ids;
var combPages = config.Pages;
var maxSec = _targetPage / section.Pages;
for (var a = 1; a <= maxSec; a++)
{
combName = combName + section.Name;
combIds = combIds + section.Id.ToString();
combPages = combPages + section.Pages;
var subConfig = new Config
{
Name = combName,
Ids = combIds,
Pages = combPages
};
if (subConfig.Pages == _targetPage)
{
_result.Add(subConfig);
break;
}
else if (subConfig.Pages < _targetPage)
{
GoDeeperAndAddToResult(subConfig, b + 1);
}
else
{
break;
}
}
}
}
public class Config
{
public string Name { get; set; }
public string Ids { get; set; }
public int Pages { get; set; }
}
public class Section
{
public int Id { get; set; }
public int Pages { get; set; }
public string Name { get; set; }
}
}

How can I organize this data into the objects I want with LINQ?

I have an the following class I'm trying to create a list of with a bunch of data I have queried:
public class Agency
{
public string AgencyName { get; set; }
public int AgencyID { get; set; }
public IEnumerable<AuditRule> rules { get; set; }
}
Where "AuditRule" is:
public class AuditRule
{
public int AuditRuleID { get; set; }
public string AuditRuleName { get; set }
public int AvgDaysWorked { get; set; }
}
Right now, after a fairly complicated query I have been able to get my data into an anonymous object that looks like:
{ DateImported, AgencyID, AgencyName, AuditRuleName, AuditRuleID, DaysWorked }
I have thousands of records in that format, and I'm trying to construct a IEnumerable<Agency> which will itself contain a list of rules for each agency.
So, take the following data as an example:
{ AgencyID = 1, AgencyName = "CCR", AuditRuleName = "Call", AuditRuleID = 1, DaysWorked = 3 }
{ AgencyID = 1, AgencyName = "CCR", AuditRuleName = "Call", AuditRuleID = 1, DaysWorked = 5 }
{ AgencyID = 1, AgencyName = "CCR", AuditRuleName = "Time", AuditRuleID = 2, DaysWorked = 2 }
{ AgencyID = 2, AgencyName = "YRX", AuditRuleName = "Call", AuditRuleID = 1, DaysWorked = 3 }
{ AgencyID = 2, AgencyName = "YRX", AuditRuleName = "Acct", AuditRuleID = 3, DaysWorked = 2 }
So, out of this data, I'm trying to construct first a list of agencies (the class at the top), which would obviously be "CCR" and "YRX" for this example. Then, for each agency I want an entry for each of its rules in its IEnumerable<AuditRule> that there is a record for.
So, Agency "CCR" would have have 2 Rule entries, "Call" and "Time". The "Call" AuditRule entry will have an AvgDaysWorked of 4 since we are averaging the entries for "Call" under Agency "CCR" which is 3 days and 5 days worked. The Time AuditRule entry would have an AvgDaysWorked of 2, since there is only one entry.
Can someone with some LINQ ninja skills please help me wrangle this data into a list of Agencies and Rules for each agency (with the avg of days worked for that rule/agency combo)?
It was complicated enough for me to even be able to get together that anonymous object and I'm really struggling writing this query to create this list of Agencies/AuditRules.
Is this a case where I would use SelectMany() or something similar? I'm kind of lost here.
I hope this does the job.
// GetAnonymousCollection() is hard to define... ;)
var anonymous = GetAnonymousCollection();
IEnumerable<Agency> result = anonymous
.GroupBy(a => a.AgencyID)
.Select(ag => new Agency()
{
AgencyID = ag.Key,
AgencyName = ag.First().AgencyName,
Rules = ag
.GroupBy(agr => agr.AudiRuleID)
.Select(agrg => new AuditRule()
{
AuditRuleID = agrg.Key,
AuditRuleName = agrg.First().AuditRuleName,
AvgDaysWorked = (Int32)agrg.Average(agrgr => agrgr.DaysWorked)
})
});
By the way, think about using a decimal or float for the average time.
EDIT: I think I personally prefer Daniel's solution in terms of simplicity, although mine is slightly more efficient (as it doesn't need to evaluate the query multiple times through calling First() to get the agency/audit rule name). I'm not entirely sure what to do with my answer here: it shows something different (grouping by a composite key) which is nice, but at the same time it's a bulky and unwieldy bit of code. Then again, it's a complete example, which makes it easier to play with...
Thoughts, anyone? Should I leave this here, or delete it?
Okay, I think this does what you want. It's pretty evil though. I don't have time to explain it immediately, but the GroupBy method is the crucial one.
I've formatted it a bit, but it's still not ideal...
using System;
using System.Collections.Generic;
using System.Linq;
public class Agency
{
public string AgencyName { get; set; }
public int AgencyID { get; set; }
public IEnumerable<AuditRule> Rules { get; set; }
public override string ToString()
{
return string.Format("Agency {0}/{1}:\r\n{2}",
AgencyID, AgencyName,
string.Concat(Rules.Select(x => x.ToString() + "\r\n")
.ToArray()));
}
}
public class AuditRule
{
public int AuditRuleID { get; set; }
public string AuditRuleName { get; set; }
public int AvgDaysWorked { get; set; }
public override string ToString()
{
return string.Format("Audit rule {0}/{1}: {2}", AuditRuleID,
AuditRuleName, AvgDaysWorked);
}
}
class Test
{
static void Main()
{
var previousQuery = new[]
{
new { AgencyID = 1, AgencyName = "CCR",
AuditRuleName = "Call", AuditRuleID = 1, DaysWorked = 3 },
new { AgencyID = 1, AgencyName = "CCR",
AuditRuleName = "Call", AuditRuleID = 1, DaysWorked = 5 },
new { AgencyID = 1, AgencyName = "CCR",
AuditRuleName = "Time", AuditRuleID = 2, DaysWorked = 2 },
new { AgencyID = 2, AgencyName = "YRX",
AuditRuleName = "Call", AuditRuleID = 1, DaysWorked = 3 },
new { AgencyID = 2, AgencyName = "YRX",
AuditRuleName = "Acct", AuditRuleID = 3, DaysWorked = 2 },
};
var itemsGroupedByAgency = previousQuery.GroupBy
(item => new { item.AgencyID, item.AgencyName });
// Want to do the query for each group
var query = itemsGroupedByAgency.Select
// Outdented to avoid scrolling
(group => new Agency
{
AgencyName = group.Key.AgencyName,
AgencyID = group.Key.AgencyID,
Rules = group.GroupBy(item => new { item.AuditRuleName,
item.AuditRuleID },
(key, items) => new AuditRule
// Outdented to avoid scrolling :)
{
AuditRuleID = key.AuditRuleID,
AuditRuleName = key.AuditRuleName,
AvgDaysWorked = (int) items.Average(x => x.DaysWorked)
})
});
foreach (var item in query)
{
Console.WriteLine(item);
}
}
}

Categories