C# 如何依赖应用程序实例对方法进行单元测试
在我的C# 如何依赖应用程序实例对方法进行单元测试,c#,unit-testing,xamarin.forms,C#,Unit Testing,Xamarin.forms,在我的ItemsViewModel中有一个方法LoadItems(),它应该用SQLite数据库中的项填充视图模型的属性 如何对该方法进行单元测试,以确保使用数据库中的内容正确更新my Items属性 我想我必须以某种方式模拟数据库,但如果不重写LoadItems()方法本身,我就不知道如何进行模拟 public class ItemsViewModel : BaseViewModel { public ObservableCollection<Item> Items { g
ItemsViewModel
中有一个方法LoadItems()
,它应该用SQLite数据库中的项填充视图模型的属性
如何对该方法进行单元测试,以确保使用数据库中的内容正确更新my Items属性
我想我必须以某种方式模拟数据库,但如果不重写LoadItems()
方法本身,我就不知道如何进行模拟
public class ItemsViewModel : BaseViewModel
{
public ObservableCollection<Item> Items { get; set; }
public ItemsViewModel() { ... }
void LoadItems()
{
Items.Clear();
var items = App.Database.GetItems();
foreach (var item in items)
Items.Add(item);
}
}
public类ItemsViewModel:BaseViewModel
{
公共ObservableCollection项{get;set;}
public ItemsViewModel(){…}
void LoadItems()
{
Items.Clear();
var items=App.Database.GetItems();
foreach(项目中的var项目)
项目。添加(项目);
}
}
:不要将其他类型的静态
成员用于IO(数据库等)等外部服务
(您的数据库操作应该是异步的
)
将您的类更改为:
public class ItemsViewModel : BaseViewModel
{
private readonly IDatabase db;
public ItemsViewModel( IDatabase database )
{
this.db = database ?? throw new ArgumentNullException(nameof(database));
this.Items = new ObservableCollection<Item>();
}
public ObservableCollection<Item> Items { get; }
public async Task LoadItemsAsync()
{
// (Show an activity indicator here and disable other inputs)
this.Items.Clear();
var items = await this.db.GetItemsAsync();
this.Items.AddRange( items );
// (Hide the activity indicator here)
}
}
然后,为了测试它,您可以提供自己的IDatabase
,它可以是为测试而创建的,也可以是作为IClassFixture
而不使用MyViewModelLocator
(请注意,xUnit的IClassFixture
与DI不同):
或:
公共类项目测试:IClassFixture
{
私有只读IDatabase数据库;
公共项目测试(IDatabase db)
{
this.db=db??抛出新的ArgumentNullException(nameof(db));
}
[事实]
公共异步任务加载\u项\u通过\u ronseal\u质询()
{
ItemsViewModel vm=新的ItemsViewModel(this.db);
Assert.Equal(0,vm.Items.Count);
等待vm.LoadItemsAsync();
Assert.Equal(5,vm.Items.Count);
}
}
public static class MyViewModelLocator
{
private static readonly IContainer _container = RegisterDependencies();
private static IContainer RegisterDependencies()
{
return new ContainerBuilder()
// Register services (this is required):
.RegisterType<IDatabase,MyDatabase>()
// Register consumers (this is optional and only needed if you're using the ViewModelLocator pattern in your XAML views):
.RegisterSingleton<ItemsViewModel>()
.Build();
}
public static IContainer Container => _container;
public static ItemsViewModel ItemsViewModel => _container.Resolve<ItemsViewModel();
}
public class ItemsTests
{
[Fact]
public async Task Load_items_passes_the_ronseal_challenge()
{
using( IDatabase testDatabase = new FakeDatabase() )
{
ItemsViewModel vm = new ItemsViewModel( db );
Assert.Equal( 0, vm.Items.Count );
await vm.LoadItemsAsync();
Assert.Equal( 5, vm.Items.Count );
}
}
}
public class ItemsTests : IClassFixture<IDatabase>
{
private readonly IDatabase db;
public ItemsTests( IDatabase db )
{
this.db = db ?? throw new ArgumentNullException(nameof(db));
}
[Fact]
public async Task Load_items_passes_the_ronseal_challenge()
{
ItemsViewModel vm = new ItemsViewModel( this.db );
Assert.Equal( 0, vm.Items.Count );
await vm.LoadItemsAsync();
Assert.Equal( 5, vm.Items.Count );
}
}