这个问题更多是关于在SpecFlow中共享值的一般性讨论。请根据您在SpecFlow中的经验提供您可能提供的任何建设性反馈。
我对这项技术比较陌生,在寻找在步骤定义文件之间共享价值的解决方案时,我找到了ScenarioContext.Current.Get
和ScenarioContext.Current.Set
。这些非常方便,但正如我所看到的,存在一些问题。
我想出了一个抽象概念,我认为这有点容易让人感觉更容易接受,我想知道人们怎么想。
问题:我的价值已设定?
我的解决方案是将ScenarioContext.Current
包装在单例访问器类中。此类的行为与ScenarioContext.Current
类似,只是在无法找到值时抛出AssertInconclusiveException
。
private static ScenarioContextAccessor instance;
public static ScenarioContextAccessor Instance
{
get
{
if (instance == null)
{
instance = new ScenarioContextAccessor();
}
return instance;
}
}
private ScenarioContextAccessor() { }
public T Retrieve<T>(string index)
{
try
{
T val = (T)ScenarioContext.Current[index];
if (val == null)
{
throw new Exception();
}
return val;
}
catch
{
throw new AssertInconclusiveException(index + " of type " + typeof(T).Name + " was not found in the current scenario context. Did you execute your steps out of order?");
}
}
public T Retrieve<T>()
{
try
{
T val = ScenarioContext.Current.Get<T>();
if (val == null)
{
throw new Exception();
}
return val;
}
catch
{
throw new AssertInconclusiveException("No object of type " + typeof(T).Name+ " could be found in the current scenario context. Did you execute your steps out of order?");
}
}
public void Set(string index, object value)
{
ScenarioContext.Current[index.ToLower(CultureInfo.InvariantCulture)] = value;
}
public void Set<T>(T value)
{
ScenarioContext.Current.Set<T>(value);
}
}
问题:这需要输入太多内容!
我的解决方案是让任何步骤定义要求这些值将它们定义为由ScenarioContextAccessor
备份的私有属性。访问值类型的任何属性都使用字符串常量作为索引。
private string FolderName
{
get
{
return ScenarioContextAccessor.Instance.Retrieve<string>(FolderingScenarioContextKey.FolderName);
}
set
{
ScenarioContextAccessor.Instance.Set(FolderingScenarioContextKey.FolderName, value);
}
}
private UserDocumentMetadata Metadata
{
get
{
return ScenarioContextAccessor.Instance.Retrieve<UserDocumentMetadata>();
}
set
{
ScenarioContextAccessor.Instance.Set<UserDocumentMetadata>(value);
}
}
所以现在我可以像访问简单的属性一样轻松访问我的共享值。
请提供您可能提供的任何建设性反馈。谢谢!
答案 0 :(得分:0)
至于第1部分,我不同意。 如果没有为数据设置正确,我发现测试失败更有用。
至于第2部分,我已经使用了这样的模式,特别是为了获得被测试对象的实例,因为它节省了大量的输入和输入。潜在的错误。
如果你只需要一个类的虚拟实例,那么另一种模式(取决于环境)而不是你的第1部分解决方案是一种懒惰的初始化方法:
public static Mock<T> GetOrMockAndStore<T>() where T : class
{
Mock<T> output;
if (ScenarioContext.Current.TryGetValue(out output))
{
return output;
}
else
{
output = new Mock<T>();
ScenarioContext.Current.Set(output);
}
return card;
}
我正在使用Moq - 非常有用的框架。
答案 1 :(得分:0)
我认为您正在寻找的功能是Context Injection(依赖注入): https://github.com/techtalk/SpecFlow/wiki/Context-Injection
这使您可以在步骤定义之间共享类。