无法通过单元测试中的 Sitecore 上下文访问 Sitecore 模拟项目(MS Fakes)
Not able to Access Sitecore Mock Items (MS Fakes) through Sitecore Context in Unit Tests
我正在尝试为 MVC5 上使用 GlassMapper[=34] 的现有 Sitecore 项目编写单元测试=] ORM 和 TDS。我使用 Jeff Sulit 的这个极其有益的博客 Post 嘲笑了 Sitecore 内容树、Sitecore 上下文、项目属性、字段集合和基础项目。
https://oddeven.ch/blog/mocking-sitecore-using-ms-fakes/
现在在上面post中建立的设置(上面共享为link.... 请在回答之前检查一下)。我在我的业务层中将上述设置保存在单独的 class 文件 UnitTestAssist.cs 中。
现在我已经编写了以下基本单元测试,其中我从我的单元测试项目创建了一个假项目,然后通过 [=43 的 UnitTestAssist class 对象的对象访问它=],Database.GetItem 调用其中 returns 为空。
namespace MySiteCoreUnitTest
{
[TestClass]
public class DataFetch
{
IDisposable _context;
readonly MySiteCoreUnitTest.UnitTestAssist _scFaker = new MySiteCoreUnitTest.UnitTestAssist();
[TestInitialize]
public void Initialize()
{
_context = ShimsContext.Create();
_scFaker.Initialize();
}
[TestCleanup]
public void Cleanup()
{
_context.Dispose();
}
[TestMethod]
public void TestingDataFetch()
{
List<ShimField> lstfields = new List<ShimField>();
//Arrange
ShimField dummyField = new ShimField()
{
IDGet = () => ID.NewID,
NameGet = () => "Ava_Title",
ValueGet = () => "This is Crazy"
};
lstfields.Add(dummyField);
var expectedItem = _scFaker.CreateFakeItem(_scFaker.Home, "sample item", (itemName, inputField) => { inputField = lstfields; });
// Act:
var actualItem = Context.Database.GetItem(expectedItem.Instance.Paths.FullPath);
var actualItemFields = actualItem.Fields; // On Debugging i get the field i added forcefully inside **UnitTestAssist**.
// Assert:
Assert.AreEqual(expectedItem, actualItem);
}
}
}
这是我用来创建模拟物品的代码。
namespace MySiteCoreUnitTest
{
public class UnitTestAssist
{
private readonly Language ContextLanguage = Language.Parse("en");
ShimItem CreateFakeItem(ShimItem parentItem, string name, Action<ShimItem, ShimTemplateItem, List<ShimField>> onItemCreating)
{
var id = ID.NewID;
var item = new ShimItem()
{
// Assigning ID.NewID directly will return a new ID every time item.ID is called
IDGet = () => id,
KeyGet = () => name.ToLower(),
NameGet = () => name,
HasChildrenGet = () => false,
ParentGet = () => parentItem,
PathsGet = () =>
{
var path = (parentItem != null ? parentItem.Instance.Paths.Path : "") + "/" + name;
return new ShimItemPath()
{
PathGet = () => path,
FullPathGet = () => path,
};
},
LanguageGet = () => ContextLanguage,
VersionsGet = () => new ShimItemVersions() { CountGet = () => { return 1; } }
};
// Bind item to parent item
if (parentItem != null)
{
var children = parentItem.Instance.HasChildren ? parentItem.Instance.Children.ToList() : new List<Item>();
children.Add(item);
parentItem.HasChildrenGet = () => true;
parentItem.ChildrenGet = () => new ChildList(parentItem.Instance, children);
parentItem.GetChildren = () => parentItem.Instance.Children;
}
// Start faking template and field collection
var templateItem = new ShimTemplateItem();
var field = new ShimField
{
};
//var fields = new List<ShimField>();
List<ShimField> fields = new List<ShimField>();
//Arrange
ShimField dummyField = new ShimField()
{
IDGet = () => ID.NewID,
NameGet = () => "Ava_Title",
ValueGet = () => "This is Crazy"
};
fields.Add(dummyField);
// Call action to allow extension of item, template, and field collection faking
onItemCreating(item, templateItem, fields);
item.TemplateGet = () => templateItem;
item.FieldsGet = () => CreateFakeFieldCollection(item, fields);
return item;
}
// Create a dictionary to hold the field collection per item ID
private Dictionary<ID, List<ShimField>> itemFields = new Dictionary<ID, List<ShimField>>();
ShimFieldCollection CreateFakeFieldCollection(ShimItem item, List<ShimField> fields)
{
foreach (var field in fields)
field.ItemGet = () => item;
ShimField _newField = new ShimField();
var fieldCollection = new ShimFieldCollection()
{
ItemGetString = (fieldName) =>
{
_newField = fields.SingleOrDefault(n => n.Instance.Name.Equals(fieldName, StringComparison.OrdinalIgnoreCase));
return fields.SingleOrDefault(n => n.Instance.Name.Equals(fieldName, StringComparison.OrdinalIgnoreCase));
}
};
Field testField = _newField;
if (!itemFields.ContainsKey(item.Instance.ID))
itemFields.Add(item.Instance.ID, fields);
else
itemFields[item.Instance.ID] = fields;
fieldCollection.Bind(itemFields[item.Instance.ID]);
return fieldCollection;
}
void FakeSitecoreContext()
{
ShimContext.LanguageGet = () => ContextLanguage;
ShimContext.SiteGet = () => new ShimSiteContext()
{
ContentLanguageGet = () => ContextLanguage
};
Func<Func<Item, bool>, Item> getItem = (predicate) =>
{
Item result;
return TryGetItem(this.Sitecore.Instance.Children, predicate, out result) ? result : null;
};
ShimContext.DatabaseGet = () => new ShimDatabase()
{
GetItemString = (path) => getItem(n => n.Paths.Path.Equals(path, StringComparison.OrdinalIgnoreCase)),
GetItemStringLanguage = (path, lang) => getItem(n => n.Paths.Path.Equals(path) && (n.Language.Equals(lang) || n.Languages != null && n.Languages.Any(l => l.Name.Equals(lang.Name)))),
GetItemID = (id) => getItem(n => n.ID.Equals(id)),
GetItemIDLanguage = (id, lang) => getItem(n => n.ID.Equals(id) && (n.Language.Equals(lang) || n.Languages != null && n.Languages.Any(l => l.Name.Equals(lang.Name)))),
};
}
bool TryGetItem(ChildList children, Func<Item, bool> predicate, out Item result)
{
result = null;
if (children == null || !children.Any()) return false;
result = children.FirstOrDefault(predicate);
if (result != null) return true;
var query = children.Where(n => n.HasChildren);
if (!query.Any()) return false;
foreach (var child in query.ToArray())
{
if (TryGetItem(child.Children, predicate, out result))
return true;
}
return false;
}
void FakeBaseItem()
{
ShimBaseItem.AllInstances.ItemGetString = (baseItem, fieldName) =>
{
Item result;
TryGetItem(Sitecore.Instance.Children, (n) => object.Equals(baseItem, n), out result);
if (result != null)
{
var fields = itemFields[result.ID];
var field = fields.FirstOrDefault(n => n.Instance.Name.Equals(fieldName, StringComparison.OrdinalIgnoreCase));
if (field != null) return field.Instance.Value;
}
return string.Empty;
};
}
public ShimItem Sitecore, Content, Site, Home;
public void Initialize(Action<UnitTestAssist> onInitializing = null)
{
Sitecore = CreateFakeItem(null, "sitecore", (sitecore, someFieldSitecore) =>
{
Content = CreateFakeItem(sitecore, "content", (content, someFieldContent) =>
{
Site = CreateFakeItem(content, "site", (site, someFieldSite) =>
{
Home = CreateFakeItem(site, "home", (home, someFieldHome) =>
{
// Add more items if you must to mimic your Sitecore tree
});
});
});
});
if (onInitializing != null)
onInitializing(this);
FakeBaseItem();
FakeSitecoreContext();
}
public ShimItem CreateFakeItem(ShimItem parentItem, string name, Action<ShimItem,List<ShimField>> onItemCreating)
{
return CreateFakeItem(parentItem, name, (i, t, f) =>
{
if (onItemCreating != null)
onItemCreating(i,f);
});
}
}
}
我修改了 Jeff 的代码,使其能够接受 List<ShimField>
作为单元测试的参数,但它仍然将项目字段作为空值发送。杰夫你能帮忙吗?
如果没有看到 'UnitTestHelperClass' class 的实际代码,很难判断。如果您也可以分享它,也许它会很有用。
更新:
我重构了您的代码以解决您的问题:
var expectedItem = _scFaker.CreateFakeItem(_scFaker.Home, "sample item", (itemName, inputField) => { inputField.AddRange(lstfields); });
我正在尝试为 MVC5 上使用 GlassMapper[=34] 的现有 Sitecore 项目编写单元测试=] ORM 和 TDS。我使用 Jeff Sulit 的这个极其有益的博客 Post 嘲笑了 Sitecore 内容树、Sitecore 上下文、项目属性、字段集合和基础项目。
https://oddeven.ch/blog/mocking-sitecore-using-ms-fakes/
现在在上面post中建立的设置(上面共享为link.... 请在回答之前检查一下)。我在我的业务层中将上述设置保存在单独的 class 文件 UnitTestAssist.cs 中。
现在我已经编写了以下基本单元测试,其中我从我的单元测试项目创建了一个假项目,然后通过 [=43 的 UnitTestAssist class 对象的对象访问它=],Database.GetItem 调用其中 returns 为空。
namespace MySiteCoreUnitTest
{
[TestClass]
public class DataFetch
{
IDisposable _context;
readonly MySiteCoreUnitTest.UnitTestAssist _scFaker = new MySiteCoreUnitTest.UnitTestAssist();
[TestInitialize]
public void Initialize()
{
_context = ShimsContext.Create();
_scFaker.Initialize();
}
[TestCleanup]
public void Cleanup()
{
_context.Dispose();
}
[TestMethod]
public void TestingDataFetch()
{
List<ShimField> lstfields = new List<ShimField>();
//Arrange
ShimField dummyField = new ShimField()
{
IDGet = () => ID.NewID,
NameGet = () => "Ava_Title",
ValueGet = () => "This is Crazy"
};
lstfields.Add(dummyField);
var expectedItem = _scFaker.CreateFakeItem(_scFaker.Home, "sample item", (itemName, inputField) => { inputField = lstfields; });
// Act:
var actualItem = Context.Database.GetItem(expectedItem.Instance.Paths.FullPath);
var actualItemFields = actualItem.Fields; // On Debugging i get the field i added forcefully inside **UnitTestAssist**.
// Assert:
Assert.AreEqual(expectedItem, actualItem);
}
}
}
这是我用来创建模拟物品的代码。
namespace MySiteCoreUnitTest
{
public class UnitTestAssist
{
private readonly Language ContextLanguage = Language.Parse("en");
ShimItem CreateFakeItem(ShimItem parentItem, string name, Action<ShimItem, ShimTemplateItem, List<ShimField>> onItemCreating)
{
var id = ID.NewID;
var item = new ShimItem()
{
// Assigning ID.NewID directly will return a new ID every time item.ID is called
IDGet = () => id,
KeyGet = () => name.ToLower(),
NameGet = () => name,
HasChildrenGet = () => false,
ParentGet = () => parentItem,
PathsGet = () =>
{
var path = (parentItem != null ? parentItem.Instance.Paths.Path : "") + "/" + name;
return new ShimItemPath()
{
PathGet = () => path,
FullPathGet = () => path,
};
},
LanguageGet = () => ContextLanguage,
VersionsGet = () => new ShimItemVersions() { CountGet = () => { return 1; } }
};
// Bind item to parent item
if (parentItem != null)
{
var children = parentItem.Instance.HasChildren ? parentItem.Instance.Children.ToList() : new List<Item>();
children.Add(item);
parentItem.HasChildrenGet = () => true;
parentItem.ChildrenGet = () => new ChildList(parentItem.Instance, children);
parentItem.GetChildren = () => parentItem.Instance.Children;
}
// Start faking template and field collection
var templateItem = new ShimTemplateItem();
var field = new ShimField
{
};
//var fields = new List<ShimField>();
List<ShimField> fields = new List<ShimField>();
//Arrange
ShimField dummyField = new ShimField()
{
IDGet = () => ID.NewID,
NameGet = () => "Ava_Title",
ValueGet = () => "This is Crazy"
};
fields.Add(dummyField);
// Call action to allow extension of item, template, and field collection faking
onItemCreating(item, templateItem, fields);
item.TemplateGet = () => templateItem;
item.FieldsGet = () => CreateFakeFieldCollection(item, fields);
return item;
}
// Create a dictionary to hold the field collection per item ID
private Dictionary<ID, List<ShimField>> itemFields = new Dictionary<ID, List<ShimField>>();
ShimFieldCollection CreateFakeFieldCollection(ShimItem item, List<ShimField> fields)
{
foreach (var field in fields)
field.ItemGet = () => item;
ShimField _newField = new ShimField();
var fieldCollection = new ShimFieldCollection()
{
ItemGetString = (fieldName) =>
{
_newField = fields.SingleOrDefault(n => n.Instance.Name.Equals(fieldName, StringComparison.OrdinalIgnoreCase));
return fields.SingleOrDefault(n => n.Instance.Name.Equals(fieldName, StringComparison.OrdinalIgnoreCase));
}
};
Field testField = _newField;
if (!itemFields.ContainsKey(item.Instance.ID))
itemFields.Add(item.Instance.ID, fields);
else
itemFields[item.Instance.ID] = fields;
fieldCollection.Bind(itemFields[item.Instance.ID]);
return fieldCollection;
}
void FakeSitecoreContext()
{
ShimContext.LanguageGet = () => ContextLanguage;
ShimContext.SiteGet = () => new ShimSiteContext()
{
ContentLanguageGet = () => ContextLanguage
};
Func<Func<Item, bool>, Item> getItem = (predicate) =>
{
Item result;
return TryGetItem(this.Sitecore.Instance.Children, predicate, out result) ? result : null;
};
ShimContext.DatabaseGet = () => new ShimDatabase()
{
GetItemString = (path) => getItem(n => n.Paths.Path.Equals(path, StringComparison.OrdinalIgnoreCase)),
GetItemStringLanguage = (path, lang) => getItem(n => n.Paths.Path.Equals(path) && (n.Language.Equals(lang) || n.Languages != null && n.Languages.Any(l => l.Name.Equals(lang.Name)))),
GetItemID = (id) => getItem(n => n.ID.Equals(id)),
GetItemIDLanguage = (id, lang) => getItem(n => n.ID.Equals(id) && (n.Language.Equals(lang) || n.Languages != null && n.Languages.Any(l => l.Name.Equals(lang.Name)))),
};
}
bool TryGetItem(ChildList children, Func<Item, bool> predicate, out Item result)
{
result = null;
if (children == null || !children.Any()) return false;
result = children.FirstOrDefault(predicate);
if (result != null) return true;
var query = children.Where(n => n.HasChildren);
if (!query.Any()) return false;
foreach (var child in query.ToArray())
{
if (TryGetItem(child.Children, predicate, out result))
return true;
}
return false;
}
void FakeBaseItem()
{
ShimBaseItem.AllInstances.ItemGetString = (baseItem, fieldName) =>
{
Item result;
TryGetItem(Sitecore.Instance.Children, (n) => object.Equals(baseItem, n), out result);
if (result != null)
{
var fields = itemFields[result.ID];
var field = fields.FirstOrDefault(n => n.Instance.Name.Equals(fieldName, StringComparison.OrdinalIgnoreCase));
if (field != null) return field.Instance.Value;
}
return string.Empty;
};
}
public ShimItem Sitecore, Content, Site, Home;
public void Initialize(Action<UnitTestAssist> onInitializing = null)
{
Sitecore = CreateFakeItem(null, "sitecore", (sitecore, someFieldSitecore) =>
{
Content = CreateFakeItem(sitecore, "content", (content, someFieldContent) =>
{
Site = CreateFakeItem(content, "site", (site, someFieldSite) =>
{
Home = CreateFakeItem(site, "home", (home, someFieldHome) =>
{
// Add more items if you must to mimic your Sitecore tree
});
});
});
});
if (onInitializing != null)
onInitializing(this);
FakeBaseItem();
FakeSitecoreContext();
}
public ShimItem CreateFakeItem(ShimItem parentItem, string name, Action<ShimItem,List<ShimField>> onItemCreating)
{
return CreateFakeItem(parentItem, name, (i, t, f) =>
{
if (onItemCreating != null)
onItemCreating(i,f);
});
}
}
}
我修改了 Jeff 的代码,使其能够接受 List<ShimField>
作为单元测试的参数,但它仍然将项目字段作为空值发送。杰夫你能帮忙吗?
如果没有看到 'UnitTestHelperClass' class 的实际代码,很难判断。如果您也可以分享它,也许它会很有用。
更新: 我重构了您的代码以解决您的问题:
var expectedItem = _scFaker.CreateFakeItem(_scFaker.Home, "sample item", (itemName, inputField) => { inputField.AddRange(lstfields); });