Reputation: 53
Code example:
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
}
}
}
Now, I want to test the check nulls, permissions and data access, is it possible? Or do I have to extract interface from the internal methods?
PS, this is for my unit testing. I'm trying to eliminate external dependencies. please explain in detail
Upvotes: 0
Views: 840
Reputation: 7475
The reason for mocking is so that you can control behaviour; in this case, I'm going to go out on a limb and guess that Service<RequestObject>
doesn't actually have any behaviour, and therefore it doesn't actually need to be mocked. So it can probably just be passed as-is in any tests.
However, if it does have behaviour, and that behaviour crosses an architectural boundary (let's say in the GetData
method you are calling some method on the request
parameter that will make a network call, or access the file system, etc.) then you do need to mock it. But you can do that easily enough:
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.
};
}
Then change GetData
to take an IService<RequestObject>
; now your calling code can instantiate a ServiceObject
in place of a Service and pass it to the GetData
method. Plus you can Mock any methods on the interface as you need. Obviously if you don't control the calling code, that's a problem since whoever is writing that code needs to do it, but that's a conversation you will need to have with them :)
In terms of testing the internal operations,you need to look at how you can abstract any dependent behaviours used by the GetData
method - for example, the contextEntity
, the CheckForNull
, the ValidateMethod
, etc - all of these are candidates to be extracted into their own abstractions and injected into the MyConcreteClass
as dependencies, e.g.:
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;
}
}
Now you can write tests for MyConcreteClass
and use mocked implementations of the dependencies, to ensure that the GetData method correctly uses them.
**and I will guess that this can be replaced with a simple if request==null throw new ArgumentNullException()
which is cleaner and simpler anyway.
Upvotes: 0
Reputation: 4885
Unit testing private methods should not be needed directly, only indirectly via public methods. If you think you testing a public method isn't enough precise, it might be that the method and the class are too complicated already.
In that case consider creating one or more new classes where the new code is located. That way you can unit test your code via public method. The added benefit is that your code is probably better in terms of Single responsibility principle.
Upvotes: 1