我有下面的类和类别项映射的字典
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" } }
};
我想以这样的方式创建 InfoClass 模拟对象,InfoClass 的 InfoID 应该是从字典内的列表中随机生成的。根据所选 InfoID 的类别,为 EDDetails 或 EVDetials 分配一个值。
例如,如果 ReportId 的随机值为“XYZ”,则 InfoID 的类别为 ITEMCATEGORY_ED,则将 {根据逻辑生成数据} 值分配给 EDDetails 属性,所有其他属性 EVDetails 都应为空。
为了实现这一目标,我尝试使用下面的方法创建自定义。
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>();
但这并没有奏效。连个例外都没有。所以尝试了下面
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>();
使用第二种方法,在调试时,我可以看到分配给 GetItemInfo 方法内的属性的数据/值。但是,一旦它返回对象并分配给“mockedvalue”,方法内部生成的数据就会消失,并生成没有自定义逻辑的新模拟数据。
我的逻辑有问题吗?或者我错过了什么?
对我来说,你的
InfoClass
看起来好像有额外的创建逻辑,所以我会将该逻辑分离到某种 InfoClassHelper
类中,如下所示:
public class InfoClassHelper
{
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" } }
};
public static string[] AvailableReports { get; } = ItemsMap.Values.SelectMany(x => x).ToArray();
public static string GetInfoIdBasedOnReport(string infoId)
{
if (!AvailableReports.Contains(infoId)) return null;
return ItemsMap
.First(x => x.Value.Contains(infoId, StringComparer.OrdinalIgnoreCase))
.Key;
}
}
然后使用这个类,使用 AutoFixture 创建
InfoClass
的对象会更容易,如下所示:
var autoFixture = new Fixture();
var index = new Random().Next(InfoClassHelper.AvailableReports.Length);
var randomReportId = InfoClassHelper.AvailableReports[index];
var infoClass = autoFixture
.Build<InfoClass>()
.With(x => x.InfoID, InfoClassHelper.GetInfoIdBasedOnReport(randomReportId))
.Create();
编辑
阅读评论后,您可以像下面这样实现工厂类:
public class InfoClassFactory
{
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" } }
};
public static string[] AvailableReports { get; } = ItemsMap.Values.SelectMany(x => x).ToArray();
private static string CreateInfoClass(string infoId)
{
return new InfoClass
{
EVDetails = GetEVDetailsBasedOnReport(infoId),
EDDetails = GetEDDetailsBasedOnReport(infoId),
EVDetails = GetInfoIdBasedOnReport(infoId),
}
}
private static string GetEDDetailsBasedOnReport(string infoId)
{
// logic here
}
private static string GetEVDetailsBasedOnReport(string infoId)
{
// logic here
}
private static string GetInfoIdBasedOnReport(string infoId)
{
if (!AvailableReports.Contains(infoId)) return null;
return ItemsMap
.First(x => x.Value.Contains(infoId, StringComparer.OrdinalIgnoreCase))
.Key;
}
}
换个角度思考,更多地从单元测试的角度来看,我用
ICUstomization
修改了你的解决方案。这是我的实现方式:
public class InfoClassCustomization : ICustomization
{
private readonly Dictionary<string, List<string>> ItemsMap;
public InfoClassCustomization(Dictionary<string, List<string>> ItemsMap)
{
this.ItemsMap = ItemsMap;
}
public void Customize(IFixture fixture)
{
// 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
var reportID = InfoIdPair.Value;
var edDetails = JsonConvert.SerializeObject(fixture.Create<EdDetails>());
var evDetails = JsonConvert.SerializeObject(fixture.Create<EvDetails>());
fixture.Customize<InfoClass>(c =>
{
var composer = c.With(x => x.ReportID, reportID);
// Set the correct property based on the key of the randomly selected tuple
switch (InfoIdPair.Key)
{
case Constants.ITEMCATEGORY_ED:
return composer.With(x => x.EDDetails, edDetails);
case Constants.ITEMCATEGORY_ERANDRE:
return composer.With(x => x.EVDetails, evDetails);
default:
return c;
}
});
}
}
这是示例单元测试(我认为您错过了
Fixture
的 Customize(new InfoClassCustomization(dict));
的电话):
public class UnitTest1
{
[Fact]
public void Test1()
{
// Arrange
var dict = new Dictionary<string, List<string>>
{
{ Constants.ITEMCATEGORY_ED, new List<string> { "XYZ", "IDASAS" } },
{ Constants.ITEMCATEGORY_ERANDRE, new List<string> { "SAS", "PQR" } }
};
var autoFixture = new Fixture()
.Customize(new InfoClassCustomization(dict));
// Act
var infoClass = autoFixture.Create<InfoClass>();
// Assert
var possibleReportIds = dict.Values.SelectMany(x => x);
Assert.NotNull(
possibleReportIds
.FirstOrDefault(x => x == infoClass.ReportID));
}
}