已经决定使用moq等编写一些单元测试.它有很多遗留代码c#
(这是我无法控制的,所以不能回答这个问题)
现在,如果您不想访问数据库但间接仍然访问数据库,您如何应对这种情况?
这是我把它放在一起的东西,它不是真正的代码,而是给你一个想法.
你会如何处理这种情况?
基本上在模拟接口上调用一个方法仍然会调用dal调用,因为在该方法中有其他方法不属于该接口的一部分?希望它清楚
[TestFixture]
public class Can_Test_this_legacy_code
{
[Test]
public void Should_be_able_to_mock_login()
{
var mock = new Mock<ILoginDal>();
User user;
var userName = "Jo";
var password = "password";
mock.Setup(x => x.login(It.IsAny<string>(), It.IsAny<string>(),out user));
var bizLogin = new BizLogin(mock.Object);
bizLogin.Login(userName, password, out user);
}
}
public class BizLogin
{
private readonly ILoginDal _login;
public BizLogin(ILoginDal login)
{
_login = login;
}
public void Login(string userName, string password, out User user)
{
//Even if I dont want to this will call the DAL!!!!!
var bizPermission = new BizPermission();
var permissionList = bizPermission.GetPermissions(userName);
//Method I am actually testing
_login.login(userName,password,out user);
}
}
public class BizPermission
{
public List<Permission>GetPermissions(string userName)
{
var dal=new PermissionDal();
var permissionlist= dal.GetPermissions(userName);
return permissionlist;
}
}
public class PermissionDal
{
public List<Permission> GetPermissions(string userName)
{
//I SHOULD NOT BE GETTING HERE!!!!!!
return new List<Permission>();
}
}
public interface ILoginDal
{
void login(string userName, string password,out User user);
}
public interface IOtherStuffDal
{
List<Permission> GetPermissions();
}
public class Permission
{
public int Id { get; set; }
public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
有什么建议?我错过了明显的吗?这是Untestable代码吗?
非常感谢任何建议.
就像现在一样,它是BizLogin不可测试的,因为它直接实例BizPermission化PermissionDal,然后实例化,然后命中数据库.
最好的解决方案是重构BizLogin以BizPermission通过调用工厂(方法)或依赖注入来替换直接实例化.从你的帖子中我不清楚你是否可以重构代码 - 如果是这样,这是首选的解决方案.
但是,如果重构不是一个选项,你仍然可以尝试一个讨厌的技巧.这在Java中是可能的,我不太了解C#,但由于这两种语言非常相似,我想在C#中也可以实现(尽管我无法填写确切的技术细节).
您可以BizPermission使用不同的模拟实现替换已编译的类文件以进行单元测试.这当然是有风险的,因为您必须确保替代实现不会混入您的生产程序集中.此外,它需要一些混乱的类路径和东西.所以,只有尝试重构才真的,绝对是不可能的.
(使用Java术语 - 我希望C#也足够清楚......)基本思想是运行时正在类路径上查找类,并且它会加载它在类路径中找到的第一个合适的类定义.因此,您可以BizPermission在单元测试源文件夹中创建一个模拟实现,在完全相同的包中,并使用与原始相同的接口.然后把它编译成例如一个test-classes文件夹(而你的生产代码被编译成例如classes).现在,如果您将测试类路径设置test-classes为之前classes,运行时将BizPermission在BizLogin尝试实例化此类时运行测试而不是原始测试时加载假类.
public class BizLogin
{
private readonly ILoginDal _login;
public BizLogin(ILoginDal login)
{
_login = login;
}
protected BizPermission getBizPermission()
{
return new BizPermission();
}
public void Login(string userName, string password, out User user)
{
var bizPermission = getBizPermission();
var permissionList = bizPermission.GetPermissions(userName);
//Method I am actually testing
_login.login(userName,password,out user);
}
}
Run Code Online (Sandbox Code Playgroud)
在测试代码中:
public class FakeBizPermission implements BizPermission
{
public List<Permission>GetPermissions(string userName)
{
// produce and return fake permission list
}
}
public class BizLoginForTest
{
public BizLoginForTest(ILoginDal login)
{
super(login);
}
protected BizPermission getBizPermission()
{
return new FakeBizPermission();
}
}
Run Code Online (Sandbox Code Playgroud)
这样,您可以通过BizLoginForTest对原始BizLogin类的最小更改来测试关键功能.
另一种方法是注入一个完整的工厂对象,如Jeff的评论中所述.这将需要更多的代码更改(可能包括在客户端中BizLogin),因此它更具侵入性.
请注意,此类重构的主要目标始终是允许进行单元测试,而不是为了获得新设计的美感而获奖:-)因此,最好从对现有代码的最少更改开始,这些更改允许您覆盖功能有测试.一旦您完成了测试,您就可以更自信地进行重构,以实现更清洁,更好的设计.
| 归档时间: |
|
| 查看次数: |
275 次 |
| 最近记录: |