前几天,我开始了一个项目,并开始沿着使用异步的道路前进,并等待它,因为我以前从未使用过它,这似乎是一个很好的匹配。我正在制作的应用程序是一个使用MVVM的WPF解决方案。它将从智能卡中读取并显示保存到智能卡中的信息。它是演示/概念的一部分。现在,视图几乎什么都没有,所以我不打算展示它。测试和ViewModel是感兴趣的。所以,让我从考试开始,因为这是我第一次在脑子里问这个问题的地方。我使用的是NUnit 3.2和Moq4.2
[TestFixture]
public class MainWindowViewModelTests
{
private Mock<ITerminalFactory> _factory;
[SetUp]
public void Setup()
{
_factory = new Mock<ITerminalFactory>();
}
[Test]
public void WhenNoTerminalIsConnected_ErrorMessageIndicatesNoTerminal()
{
_factory.Setup(f => f.EnumerateTerminals()).Returns(async ()=>
{
await Task.Yield();
return new ITerminal[0];
});
var target = GetClassUnderTest();
Assert.That(target.Error, Is.EqualTo("No Terminals"));
}
[Test]
public void WhenAtleastOneTerminalIsConnected_NoErrorMessages()
{
_factory.Setup(f => f.EnumerateTerminals()).Returns(async () =>
{
await Task.Yield();
return new ITerminal[] { Mock.Of<ITerminal>()};
});
var target = GetClassUnderTest();
Assert.That(target.Error, Is.Null.Or.Empty);
Assert.That(target.Terminals.Count, Is.EqualTo(1));
}
private MainWindowViewModel GetClassUnderTest()
{
var target = new MainWindowViewModel(_factory.Object);
while (!target.IsLoaded)
{
System.Threading.Thread.Sleep(1);
}
return target;
}
}public class MainWindowViewModel : HandleErrorsViewModel
{
public ICollection<ITerminal> Terminals { get; }
public bool IsLoaded { get; private set; }
public MainWindowViewModel(ITerminalFactory terminalFactory)
{
Terminals = new ObservableCollection<ITerminal>();
PopulateTerminals(terminalFactory);
}
private async void PopulateTerminals(ITerminalFactory terminalFactory)
{
IEnumerable<ITerminal> terminals = await terminalFactory.EnumerateTerminals();
terminals.ToList().ForEach(Terminals.Add);
if (Terminals.Count == 0)
Error = "No Terminals";
IsLoaded = true;
}
}省略了,因为它只是IDataErrorInfo的包装器,而BaseViewModel只是INotifyPropertyChanged的包装器
public interface ITerminal : System.IDisposable
{
string Name { get; }
IChippedCard Connect();
void Disconnect();
}
public interface ITerminalFactory
{
Task<IEnumerable<ITerminal>> EnumerateTerminals();
}这就是我现在的处境。我以前从未使用过异步和等待。我以前从未使用过任务作为返回方法,我总是希望使用最佳实践,所以这就是我在这里的原因。所以请让我知道你的想法/担心/建议/想法。
发布于 2016-03-29 06:09:16
我看到您在测试异步/等待中使用,所以您可以以同样的方式执行GetClassUnderTest。返回一个任务并异步地等待它。
此外,您还可以将内部while和Thread.Sleep更改为其他内容。我会将PopulateTerminals更改为public (除了Terminals集合之外,它不改变任何内部状态,您可以在验证是否已填充的填充之前进行检查),然后从测试调用中进行检查。
我认为将其公开是最好的方法,但是如果您不愿意这样做,可以考虑使用一些信号来表示关于IsLoading的信息,而不是做一些无用的事情。
我不喜欢EnumerateTerminals返回IEnumerable<ITerminal>。我不知道枚举的逻辑是什么,但是我想您从那里返回列表,所以也将返回值更改为Task<List<ITerminal>>。如果您确实返回IEnumerable,这可能是一个问题,因为懒惰。
在VM中,为什么您的集合是ICollection而不是ObservableCollection?如果您出于某种原因(排序)故意这样做,这是可以的,但如果不更改为具体类型(它更清晰,避免转换)。
例如,可以将ITerminalFactory作为属性注入VM,然后不需要传递它来填充集合。
https://codereview.stackexchange.com/questions/123931
复制相似问题