代码示例:
public interface IMyInterface
{
[OperationContract]
responseObject GetData(Service<RequestObject> request);
}
public class MyConcreteClass : IMyInterface
{
public responseObject GetData(Service<RequestObject> request)
{
CheckForNull(request);
ValidateMethod(request);
//connect to db
using(var context = new contextEntity)
{
//get data
}
}
}
现在,我想测试检查空值,权限和数据访问,是否可能?或者我是否必须从内部方法中提取接口?
PS,这是我的单元测试。我正在尝试消除外部依赖。 请详细说明
答案 0 :(得分:1)
不应直接通过公共方法间接地直接对单元测试私有方法进行测试。如果您认为测试公共方法不够精确,那么方法和类可能已经太复杂了。
在这种情况下,请考虑创建一个或多个新代码所在的新类。这样您就可以通过公共方法对代码进行单元测试。额外的好处是您的代码在Single responsibility principle.
方面可能更好答案 1 :(得分:0)
模仿的原因是你可以控制行为;在这种情况下,我会想出Service<RequestObject>
实际上没有任何行为,因此它实际上并不需要被嘲笑。所以它可能只是在任何测试中按原样传递。
但是,如果确实有行为,并且该行为跨越架构边界(让我们在GetData
方法中说你在{{1}上调用了一些方法将进行网络调用或访问文件系统等的参数,然后你需要模拟它。但你可以很容易地做到这一点:
request
然后更改public interface IService<RequestObject>
{
//put method and property signatures of Service<RequestObject> here
}
public class ServiceObject:Service<RequestObject>, IService<RequestObject>
{
public ServiceObject(RequestObject request): base(request){
//or however the Service<Request> object is instantiated.
};
}
以获取GetData
;现在,您的调用代码可以实例化IService<RequestObject>
来代替服务,并将其传递给ServiceObject
方法。另外,您可以根据需要在界面上模拟任何方法。显然,如果你不控制调用代码,这就是一个问题,因为无论谁编写代码都需要这样做,但这是你需要与他们进行的对话:)
在测试内部操作方面,您需要了解如何抽象GetData
方法使用的任何依赖行为 - 例如GetData
,contextEntity
, CheckForNull
等等 - 所有这些都被提取到他们自己的抽象中,injected被提取到ValidateMethod
作为依赖,例如:
MyConcreteClass
现在您可以编写public class MyConcreteClass: IMyInterface
{
readonly INullChecker _nullChecker;
readonly IValidator _validator;
readonly IContextEntity _context;
public MyConcreteClass(INullChecker nullChecker, IValidator validator, IContextEntity _context)
{
_nullChecker = nullChecker;
_validator = validator;
_context=context;
}
public responseObject GetData(Service<RequestObject> request)
{
_nullChecker.Check(request)//**;
_validator.Validate(request);
var result = _context.DoSomethingWith(request);
return result;
}
}
的测试并使用依赖项的模拟实现,以确保GetData方法正确使用它们。
**我猜这可以用简单的MyConcreteClass
代替,无论如何都更简洁。