使用 Moq 和 Xunit 测试接口
Using Moq and Xunit to test interfaces
我是 XUnit 和 Moq 的新手。我试图了解测试框架和准备单元测试用例。我正在使用依赖注入来注入接口。
我正在测试以下接口
using System.Collections.Generic;
using Zeiss.IMT.MCCNeo.Settings.Entities;
namespace Zeiss.IMT.MCCNeo.Settings.Data.Interface
{
public interface IProfilesRepository
{
IList<Profile> GetAllProfiles();
IList<Profile> GetProfilesMatchingUserID(string userid);
IList<Profile> GetProfilesForUserIDWithSettingName(string userid, string settingname);
}
}
实施class
using System;
using System.Collections.Generic;
using Zeiss.IMT.MCCNeo.Settings.Data.Interface;
using Zeiss.IMT.MCCNeo.Settings.Entities;
using System.Linq;
using Zeiss.IMT.MCCNeo.Settings.Data.Singleton;
using Zeiss.IMT.MCCNeo.Settings.Utilities;
namespace Zeiss.IMT.MCCNeo.Settings.Data.Repository
{
public class ProfilesRepository : IProfilesRepository
{
private IProfileDataRepository _profileDataRepository { get; set; }
public ProfilesRepository(IProfileDataRepository ProfileDataRepository)
{
_profileDataRepository = ProfileDataRepository;
}
public IList<Profile> GetAllProfiles()
{
return _profileDataRepository.Get();
}
public IList<Profile> GetProfilesMatchingUserID(string userid)
{
if (string.IsNullOrWhiteSpace(userid)) throw new ArgumentException("User Id Cannot be null");
return _profileDataRepository.Get().Where(puid => puid.UserID.ToLower() == userid.ToLower()).ToList<Profile>();
}
public IList<Profile> GetProfilesForUserIDWithSettingName(string userid, string settingname)
{
if (string.IsNullOrWhiteSpace(userid) || string.IsNullOrWhiteSpace(settingname)) throw new ArgumentException("User Id or settingname Cannot be null");
var profilesWithSettings = _profileDataRepository.Get().Where(p => p.UserID.ToLower() == userid.ToLower() & p.Settings.Any(s => s.Name.ToLower() == settingname.ToLower()));
return profilesWithSettings.ToList();
}
}
}
处理数据加载和数据保存到文件的数据存储库
using System;
using System.Collections.Generic;
using Zeiss.IMT.MCCNeo.Settings.Entities;
namespace Zeiss.IMT.MCCNeo.Settings.Data.Singleton
{
public interface IProfileDataRepository
{
List<Profile> Get();
List<Profile> Get(Func<Profile, bool> filter);
void Save(List<Profile> profilesToSave);
}
}
using System;
using System.Collections.Generic;
using Zeiss.IMT.MCCNeo.Settings.Entities;
using Zeiss.IMT.MCCNeo.Settings.Utilities;
using System.Linq;
namespace Zeiss.IMT.MCCNeo.Settings.Data.Singleton
{
public class ProfileDataRepository : IProfileDataRepository
{
private static List<Profile> profiles;
public IRepository _repository { get; set; }
public ProfileDataRepository(IRepository repository)
{
_repository = repository;
if (profiles == null)
{
profiles = repository.Get<Profile>();
}
}
public List<Profile> Get()
{
return profiles;
}
public List<Profile> Get(Func<Profile, bool> filter)
{
return profiles.Where(filter).ToList();
}
public void Save(List<Profile> profilesToSave)
{
profiles = profilesToSave;
_repository.Save<List<Profile>>(profiles);
}
}
}
我正在尝试模拟 Profile 实体,然后将其传递给模拟接口。但是,我仍然缺乏对如何模拟接口和传递数据实体的理解。
Entity class
namespace Zeiss.IMT.MCCNeo.Settings.Entities
{
public class Profile
{
public string UserID { get; set; }
public string UserName { get; set; }
public List<Setting> Settings { get; set; }
}
}
Test class
using Moq;
using System;
using System.Collections.Generic;
using System.Text;
using Zeiss.IMT.MCCNeo.Settings.Data.Interface;
using Zeiss.IMT.MCCNeo.Settings.Data.Singleton;
using Zeiss.IMT.MCCNeo.Settings.Entities;
namespace Zeiss.IMT.MCCNeo.Settings.Tests
{
public class ProfilesServiceTests
{
private readonly Mock<IProfileDataRepository> ProfileDataProvider;
private readonly Mock<IProfilesRepository> ProfilesProvider;
public ProfilesServiceTests()
{
ProfileDataProvider = new Mock<IProfileDataRepository>();
ProfilesProvider = new Mock<IProfilesRepository>();
}
public void GetProfilesMatchingUserID_WhenPassedNull_Return_Exception()
{
List<Setting> settings = new List<Setting>() {
new Setting(){
Name = "RefreshInterval",
Value = { },
Type = "string",
Encrypted = true,
ReadOnly = true,
CreatedOn = new DateTime(),
ModifiedOn = new DateTime(),
Valid = true,
Enabled = true,
Description = "Protocol Archive view renwal interval in seconds. Minimum value = 300 Maximum value = 28800"
}
};
Profile profile = new Profile()
{
UserID = "admin",
UserName = "admin",
Settings = settings
};
List<Profile> profiles = new List<Profile>()
{
profile
};
ProfileDataProvider.Setup(x => x.Get()).Returns(profiles);
ProfilesProvider.Setup(x => x.GetProfilesMatchingUserID(null)).Returns(new NullReferenceException());
}
}
}
请多多指教。
感觉就像您想一次测试所有(或很多)class。请记住,您不需要进行集成测试(目前)。
先看看你的ProfilesRepository
。
我们需要类似
的东西
public class ProfileRepositoryTests
{
//this class is only reposible to handle data from the IProfileDataRepository
private readonly ProfilesRepository _profilesRepository;
private readonly Mock<IProfileDataRepository> _moqProfileDataProvider;
public ProfileRepositoryTests()
{
_moqProfileDataProvider = new Mock<IProfileDataRepository>();
_profilesRepository = new ProfilesRepository(_moqProfileDataProvider.Object);
}
[Fact]
public void Get_Succes_NoProfiles()
{
_moqProfileDataProvider.Setup(x => x.Get()).Returns(new List<Profile>());
var profiles = _profilesRepository.GetAllProfiles();
Assert.AreEqual(0, profiles.Count);
}
[Fact]
public void Get_Succes_AllProfiles()
{
_moqProfileDataProvider.Setup(x => x.Get()).Returns(new List<Profile>
{
new Profile {UserID = "123"}
});
var profiles = _profilesRepository.GetAllProfiles();
Assert.AreEqual(1, profiles.Count);
Assert.AreEqual("123", profiles.First().UserID);
//test more properties
}
[Fact]
public void GetProfilesMatchingUserID_userId_null_Throws_Error()
{
Exception ex = Assert.Throws<ArgumentException>(() => _profilesRepository.GetProfilesMatchingUserID(null));
}
}
这并没有完成所有测试,但可以让您了解如何继续。
请记住,将所有 class/unit 测试等分开。每个测试应该只检查一个异常。请记住,单元测试只测试一件事,一种情况。如果您的代码抛出两个不同的异常,则不能在相同条件下执行。
祝你好运!
我是 XUnit 和 Moq 的新手。我试图了解测试框架和准备单元测试用例。我正在使用依赖注入来注入接口。
我正在测试以下接口
using System.Collections.Generic;
using Zeiss.IMT.MCCNeo.Settings.Entities;
namespace Zeiss.IMT.MCCNeo.Settings.Data.Interface
{
public interface IProfilesRepository
{
IList<Profile> GetAllProfiles();
IList<Profile> GetProfilesMatchingUserID(string userid);
IList<Profile> GetProfilesForUserIDWithSettingName(string userid, string settingname);
}
}
实施class
using System;
using System.Collections.Generic;
using Zeiss.IMT.MCCNeo.Settings.Data.Interface;
using Zeiss.IMT.MCCNeo.Settings.Entities;
using System.Linq;
using Zeiss.IMT.MCCNeo.Settings.Data.Singleton;
using Zeiss.IMT.MCCNeo.Settings.Utilities;
namespace Zeiss.IMT.MCCNeo.Settings.Data.Repository
{
public class ProfilesRepository : IProfilesRepository
{
private IProfileDataRepository _profileDataRepository { get; set; }
public ProfilesRepository(IProfileDataRepository ProfileDataRepository)
{
_profileDataRepository = ProfileDataRepository;
}
public IList<Profile> GetAllProfiles()
{
return _profileDataRepository.Get();
}
public IList<Profile> GetProfilesMatchingUserID(string userid)
{
if (string.IsNullOrWhiteSpace(userid)) throw new ArgumentException("User Id Cannot be null");
return _profileDataRepository.Get().Where(puid => puid.UserID.ToLower() == userid.ToLower()).ToList<Profile>();
}
public IList<Profile> GetProfilesForUserIDWithSettingName(string userid, string settingname)
{
if (string.IsNullOrWhiteSpace(userid) || string.IsNullOrWhiteSpace(settingname)) throw new ArgumentException("User Id or settingname Cannot be null");
var profilesWithSettings = _profileDataRepository.Get().Where(p => p.UserID.ToLower() == userid.ToLower() & p.Settings.Any(s => s.Name.ToLower() == settingname.ToLower()));
return profilesWithSettings.ToList();
}
}
}
处理数据加载和数据保存到文件的数据存储库
using System;
using System.Collections.Generic;
using Zeiss.IMT.MCCNeo.Settings.Entities;
namespace Zeiss.IMT.MCCNeo.Settings.Data.Singleton
{
public interface IProfileDataRepository
{
List<Profile> Get();
List<Profile> Get(Func<Profile, bool> filter);
void Save(List<Profile> profilesToSave);
}
}
using System;
using System.Collections.Generic;
using Zeiss.IMT.MCCNeo.Settings.Entities;
using Zeiss.IMT.MCCNeo.Settings.Utilities;
using System.Linq;
namespace Zeiss.IMT.MCCNeo.Settings.Data.Singleton
{
public class ProfileDataRepository : IProfileDataRepository
{
private static List<Profile> profiles;
public IRepository _repository { get; set; }
public ProfileDataRepository(IRepository repository)
{
_repository = repository;
if (profiles == null)
{
profiles = repository.Get<Profile>();
}
}
public List<Profile> Get()
{
return profiles;
}
public List<Profile> Get(Func<Profile, bool> filter)
{
return profiles.Where(filter).ToList();
}
public void Save(List<Profile> profilesToSave)
{
profiles = profilesToSave;
_repository.Save<List<Profile>>(profiles);
}
}
}
我正在尝试模拟 Profile 实体,然后将其传递给模拟接口。但是,我仍然缺乏对如何模拟接口和传递数据实体的理解。
Entity class
namespace Zeiss.IMT.MCCNeo.Settings.Entities
{
public class Profile
{
public string UserID { get; set; }
public string UserName { get; set; }
public List<Setting> Settings { get; set; }
}
}
Test class
using Moq;
using System;
using System.Collections.Generic;
using System.Text;
using Zeiss.IMT.MCCNeo.Settings.Data.Interface;
using Zeiss.IMT.MCCNeo.Settings.Data.Singleton;
using Zeiss.IMT.MCCNeo.Settings.Entities;
namespace Zeiss.IMT.MCCNeo.Settings.Tests
{
public class ProfilesServiceTests
{
private readonly Mock<IProfileDataRepository> ProfileDataProvider;
private readonly Mock<IProfilesRepository> ProfilesProvider;
public ProfilesServiceTests()
{
ProfileDataProvider = new Mock<IProfileDataRepository>();
ProfilesProvider = new Mock<IProfilesRepository>();
}
public void GetProfilesMatchingUserID_WhenPassedNull_Return_Exception()
{
List<Setting> settings = new List<Setting>() {
new Setting(){
Name = "RefreshInterval",
Value = { },
Type = "string",
Encrypted = true,
ReadOnly = true,
CreatedOn = new DateTime(),
ModifiedOn = new DateTime(),
Valid = true,
Enabled = true,
Description = "Protocol Archive view renwal interval in seconds. Minimum value = 300 Maximum value = 28800"
}
};
Profile profile = new Profile()
{
UserID = "admin",
UserName = "admin",
Settings = settings
};
List<Profile> profiles = new List<Profile>()
{
profile
};
ProfileDataProvider.Setup(x => x.Get()).Returns(profiles);
ProfilesProvider.Setup(x => x.GetProfilesMatchingUserID(null)).Returns(new NullReferenceException());
}
}
}
请多多指教。
感觉就像您想一次测试所有(或很多)class。请记住,您不需要进行集成测试(目前)。
先看看你的ProfilesRepository
。
我们需要类似
的东西public class ProfileRepositoryTests
{
//this class is only reposible to handle data from the IProfileDataRepository
private readonly ProfilesRepository _profilesRepository;
private readonly Mock<IProfileDataRepository> _moqProfileDataProvider;
public ProfileRepositoryTests()
{
_moqProfileDataProvider = new Mock<IProfileDataRepository>();
_profilesRepository = new ProfilesRepository(_moqProfileDataProvider.Object);
}
[Fact]
public void Get_Succes_NoProfiles()
{
_moqProfileDataProvider.Setup(x => x.Get()).Returns(new List<Profile>());
var profiles = _profilesRepository.GetAllProfiles();
Assert.AreEqual(0, profiles.Count);
}
[Fact]
public void Get_Succes_AllProfiles()
{
_moqProfileDataProvider.Setup(x => x.Get()).Returns(new List<Profile>
{
new Profile {UserID = "123"}
});
var profiles = _profilesRepository.GetAllProfiles();
Assert.AreEqual(1, profiles.Count);
Assert.AreEqual("123", profiles.First().UserID);
//test more properties
}
[Fact]
public void GetProfilesMatchingUserID_userId_null_Throws_Error()
{
Exception ex = Assert.Throws<ArgumentException>(() => _profilesRepository.GetProfilesMatchingUserID(null));
}
}
这并没有完成所有测试,但可以让您了解如何继续。 请记住,将所有 class/unit 测试等分开。每个测试应该只检查一个异常。请记住,单元测试只测试一件事,一种情况。如果您的代码抛出两个不同的异常,则不能在相同条件下执行。
祝你好运!