I have below class and a dictionary of category item mappings
public class InfoClass
{
public InfoClass()
{
this.InfoID = string.Empty;
this.EDDetails = string.Empty;
this.EVDetails = string.Empty;
}
public int ID { get; set;}
public string InfoID { get; set;}
public string EDDetails { get; set; }
public string EVDetails { get; set; }
}
private static Dictionary<string, List<string>> ItemsMap = new Dictionary<string, List<string>>
{
{ Constants.ITEMCATEGORY_ED, new List<string> { "XYZ", "IDASAS" } },
{ Constants.ITEMCATEGORY_ERANDRE, new List<string> { "SAS", "PQR" } }
};
I want to create the InfoClass mock object in such a way that, the InfoID of InfoClass should be random from the list inside the Dictionary. Based on that category of the selected InfoID, assign a value for EDDetails or EVDetials.
For example, If the random value of ReportId is "XYZ", then category of InfoID is ITEMCATEGORY_ED, then assign {Generate data based on a logic} value to EDDetails property and all the other properties EVDetails should be empty.
To achieve this, i tried creating a Customization using below.
public class InfoClassCustomization : ICustomization
{
private readonly Dictionary<string, List<string>> ItemsMap;
public ArchivedOrderLineItemInfoCustomization(Dictionary<string, List<string>> ItemsMap)
{
this.ItemsMap = ItemsMap;
}
public virtual void Customize(IFixture fixture)
{
fixture.Customize<InfoClass>(c => c
.Do(o =>
{
// Flatten your dictionary to a list of tuples
var keyValueList = ItemsMap.SelectMany(kvp => kvp.Value.Select(v => (Key: kvp.Key, Value: v))).ToList();
// Pick a random tuple
var InfoIdPair = keyValueList[new Random().Next(keyValueList.Count)];
// Set the ReportID from the randomly selected tuple
o.ReportID = InfoIdPair.Value;
// Set the correct property based on the key of the randomly selected tuple
switch (InfoIdPair.Key)
{
case Constants.ITEMCATEGORY_ED:
o.EDDetails = JsonConvert.SerializeObject(fixture.Create<EdDetails>());
break;
case Constants.ITEMCATEGORY_ERANDRE:
o.EVDetails = JsonConvert.SerializeObject(fixture.Create<EvDetails>());
break;
}
}));
}
}
var fixture = new Fixture().Customize(new InfoClassCustomization(ItemsMap));
var obj = fixture.Create<InfoClass>();
But this didnt worked. Didn't even got any exception. So tried below
public static InfoClass GetItemInfo()
{
var fixture = new Fixture();
InfoClass o = new InfoClass();
// Flatten your dictionary to a list of tuples
var keyValueList = ItemsMap.SelectMany(kvp => kvp.Value.Select(v => (Key: kvp.Key, Value: v))).ToList();
// Pick a random tuple
var InfoIdPair = keyValueList[new Random().Next(keyValueList.Count)];
// Set the ReportID from the randomly selected tuple
o.ReportID = InfoIdPair.Value;
// Set the correct property based on the key of the randomly selected tuple
switch (InfoIdPair.Key)
{
case Constants.ITEMCATEGORY_ED:
o.EDDetails = JsonConvert.SerializeObject(fixture.Create<EdDetails>());
break;
case Constants.ITEMCATEGORY_ERANDRE:
o.EVDetails = JsonConvert.SerializeObject(fixture.Create<EvDetails>());
break;
}
return o;
}
var fixture = new Fixture();
fixture.Customize<ArchivedOrderLineItemInfo>(c => c
.Do(o => o= GetItemInfo()));
var mockedvalue = fixture.Create<InfoClass>();
With the second approach, while i debug, i can see the data/values assigned to the properties inside the GetItemInfo method. But once it returned the object and assigned to "mockedvalue", the data generated inside the method is gone and a fresh mock data with out the custom logic is generated.
Is there any issue with my logic ? or am i missing something ?
Thinking of it other way, more from unit test perspective, I have modified your solution with
ICUstomization. Here is how I implemented it:And here is sample unit test (I think you have missed call to
Fixture'sCustomize(new InfoClassCustomization(dict));):EDIT Accordingly to comments, above method will create all objects with the same
ReportId. To correct that we can useFixture.Registermethod, as below:Now below sample unit test passes: