How to make Ninject return a mock object - linq

I have a code that looks like this
public class EmployeeController : Controller
{
public ContextWrapper contextWrapper;
public EmployeeController (IContextWrapper wrapper)
{
contextWrapper = wrapper;
}
In my dependency resolver I have the binding for IContextWrapper
kernel.Bind<IContextWrapper>().To<ContextWrapper>();
The implementation of ContextWrapper has an object which is of type Linq DataContext.
public class ContextWrapper : IContextWrapper
{
public MyDataContext dataContext;
public ContextWrapper(MyDataContext context)
{
this.dataContext = context;
}
Now my action method in this controller looks like this
var empRepository = new EmployeeRepository(contextWrapper);
//do some tests with this repository.
some values = contextWrapper.datacontext.get some values from the database table
//do some tests with these values.
To be able to test this method
I should be able to provide some sort of mock database(not literally) or
make the contextWrapper.datacontext return mocked values or
I even thought of creating another implementation of the IContextWrapper that doesn't use a Linq DataContext object. And creating another constructor for this controller and pass that fake implementation. Also in my dependency resolver I would bind the fake object to the IContextWrapper. Although I do not know how to make Ninject
As a last resort test my method against a test database since it all boils down to this Linq DataContext object and it seems I cannot get rid of it past a certain level.
Problem is the more I read about it, more I get confused. I have tried to give as much detail as possible to explain my problem. If any one has a clear cut idea about how to get this, please suggest.

Related

How to mock private method in public method in Spring Boot with JUnit

I'd like you ask a few questions and ask you for advice:
I want to test my public method (I use Spring Boot, Mockito, JUnit):
#Service
public class MyClass{
public Long getClientId(List<String> nameSurname) throws AuthorizationException {
Long operatorId;
if(...){
(... something not interesting ...)
User user = getUserByLogin("AnthonyGates2");
operatorId = nonNull(user) ? user.getOperatorId() : null;
} else {
List<User> users = getUserListByLogin("AnthinyGates");
operatorId = isNotEmpty(users) ? return operatorId;
return operatorId;
}
How to test the method getClientId?
Methods getUserByLogin and getUserListByLogin are private in this class (MyClass) but I have to mock the results of these private methods because these methods retrieve data from an external service.
These private methods looks like:
User user = DelegateImpl.getDelegate().getUserByLogin(nameAndSurname);
DelegateImpl.getDelegate().getUserByLogin get data from database and that data have to be mocked like:
when(DelegateImpl.getDelegate().getUserByLogin(any())).thenReturn(user);
How can I test my public class? Should I use PowerMock/PowerMockito? Making these methods public is in my opinion ugly because these methods are called only in MyClass. I can't find a good tutorial in Internet for my case (Spring Boot, Mockito, JUnit).
Thank you very much for all your tips!
Best regards
Matthew
Test the unit only by calling the public methods. I think that your example is a class in the service layer (contains business logic) and the two getUser... methods should be in a different class (I think in the data layer) where they can be public. Inject that class via the constructor as a dependency (in the service object) so you can mock it when testing the service class. The data layer class (with the getUser... methods) can also be tested by it's own unit tests.
If you are not able to unit test a method/class then it most probably means that it just does too much. Try extracting your private methods to a separate class. It does not need to be public - you can e.g. have it package-local in the same package.
Later, in the test, you would have to inject a mock of this class and simulate its behaviour.
The setup of MyClass in its unit test could look similar to this:
AnotherClass anotherClassMock = Mockito.mock(AnotherClass.class);
MyClass myClass = new MyClass(anotherClassMock);
Where AnotherClass would have methods getUserListByLogin and getUserByLogin.
EDIT:
It seems that the logic within in your private methods already call an external class. The problem is that you obtain an instance of an object via a call to a static getDelegate() method in another class.
Here's what you can do:
Create a new field in MyClass which would have the same type as the one returned by getDelegate() method (I don't know what that is, I'll call it Delegate)
Have 2 constructors: a default one which would assign the result of getDelegate method to your new field and another one which would take an instance of Delegate as a parameter and assign it to your field
In tests use the second constructor to create an instance of MyClass and pass a mock of Delegate class
It would look more ore less like this:
class MyClass() {
private Delegate delegate;
MyClass() {
this.delegate = DelegateImpl.getDelegate();
}
MyClass(Delegate delegate) {
this.delegate = delegate;
}
// ... the rest
}

Weird issue in Lazy load

I am totally confused with one issue Spring data + hibernate
We have a Restful service which we are migrating to V2.
So the old controller looks like
#Api(tags = {"assignments"})
#RestController
#CheckedTransactional
public class AssignmentListController {
#Inject
private AssignmentListService assignmentListService;
//REST function
public list() {....}
}
The REST function list calls AssignmentListService to load assignments, which is a collection, and loads some data lazily. Its works excellent.
What I did is I copied this controller as name AssignmentListControllerV2, and it looks like
#Api(tags = {"assignments"})
#RestController
#CheckedTransactional
public class AssignmentListControllerV2 {
#Inject
private AssignmentListService assignmentListService;
#Inject
private AssignmentDtoMapper assignmentDtoMapper;
public list() {...}
}
The code is same except AssignmentDtoMapper bean added, which is created using MapStruct.
Now the problem, When I call this new service, somehow I get a Lazy Load exception. The error is
could not initialize proxy - no Session
I desperately need some help as I have no clue whats happening. I have just copied the code in a new class and its failing.
The exception is actually pretty clear, Hibernate can't load the lazy fetched member because there is no persistence context open when you hit it.
I suppose that in the V2 the:
#Inject
private AssignmentDtoMapper assignmentDtoMapper;
is to change some JPA business entity into DTO?
It's probably the source of the exception if you try to map not loaded member there.
If you want to avoid the exception on unitiliazed proxy you can try something like
public boolean isProxyInitialized(Object obj){
if(obj instanceof HibernateProxy){
HibernateProxy proxy = (HibernateProxy) obj;
return !proxy.getHibernateLazyInitializer().isUninitialized();
}
return obj != null;
}
It should return true if the member as bean fetched otherwise false.

Getting property from injected type during registration

Hopefully I can explain this to where someone might understand it enough to help :)
Anyways, I want to take a property from an injected type and use that in another injection. So imagine you have MVC model state on a controller that you want to inject into a service the controller uses.
public class MyController
{
public MyController(IService service)
{
....
}
}
public class MyService : IService
{
public MyService(IModelStateWrapper modelState)
{
....
}
}
How can I accomplish basically this:
public class MyController
{
public MyController(IService service)
{
service.ModelState = new ModelStateWrapper(ModelState);
}
}
Using an injection with Autofac or whatever DI container.
You can do this, but you have to unravel a couple of design problems before it's possible.
First, it appears that your IService implementation requires you pass the IModelStateWrapper in during construction only to be overwritten later during the creation of the controller. You have to make it so the IService implementation only has it as a property, not as a constructor requirement.
Second, you have to make sure it's OK that the service.ModelState setting happens just after construction of the controller. If there is other constructor logic that assumes the service.ModelState is set, then you have something that can't really be done via DI.
If you do that unraveling, Autofac will let you do some pretty cool stuff. When you register your controller type, register a lambda instead of just a type.
var builder = new ContainerBuilder();
builder.RegisterType<MyService>().As<IMyService>();
builder.Register(
c=>
{
var service = c.Resolve<IMyService>();
var controller = new MyController(service);
service.ModelState = new ModelStateWrapper(controller.ModelState);
return controller;
}).As<IController>();
var container = builder.Build();
Note the circular logic thing is handled in the lambda of the registration. Now when you resolve a controller...
var controller = container.Resolve<IController>();
...that logic will run and you'll get the effect you're looking for.
Again, I'll voice some concern over the circular reference stuff going on here. If there's a way to remove that circular dependency between the controller and the service, you'd be in a better spot to let DI work for you.

Ninject Binding Issue with Constructor Chaining

I have a MVC3 project that uses the Entity Framework and Ninject v2.2, and follows the Unit of Work pattern with a Service Layer wrapping my repositories.
After looking at the code below, hopefully its apparent that Ninject is using constructor chaining to inject the correct classes. It currently works prefectly in my application, however I am at the point that I need to bind an instance of IDatabase to MyDatabase with a different scope such as InSingletonScope() or InNamedScope(), not InRequestScope(). I know that I can use the [Named("MyDatabaseScope")] Attribute to customize which IDatabase object is injected, however it seems that with my code structure, if I wanted to inject my SingletonScoped instance, I would have to recreate a new Abstract and Concrete Implementation of my Unit of Work, my Service and all my Repositories, that will then chain down.
Basically my application currently goes
Controller -> Unit of Work -> Database, (Repositories -> Database)
If I have to change my Database Binding, I will now have to create another chain in addition to the current one:
Controller -> New Unit of Work -> SingletonDatabase, (New Repositories-> SingletonDatabase)
This seems to completely defeat the DRY principal. Is there a way to, from the Controller Constructor, inform Ninject that when doing constructor chaining it should use my singleton (or named binding) rather than my request scope binding, without having to recreate all my classes with a Named attribute, or a new Interface?
Sorry for the long text, I wasnt sure if I could get the point across without my code snippets and my somewhat rambling explaination.
Ninject Module Load Function:
..snip..
Bind<IUserServices>().To<UserServices>();
Bind<IBaseServices>().To<BaseServices>();
Bind<IUserRepository>().To<UserRepository>();
Bind(typeof (IRepository<>)).To(typeof (RepositoryBase<>));
Bind<IUnitOfWork>().To<UnitOfWork>();
Bind<IDatabase>().To<MyDatabase>().InRequestScope();
//This is my problem:
//Bind<IDatabase>().To<MySingletonDatabase>().InSingletonScope();
Unit of Work Implementation Constructor:
public class UnitOfWork : IUnitOfWork
{
private IDatabase _database;
public UnitOfWork(IDatabase database,
IUserRepository userRepository,
IPeopleRepository peopleRepository,
)
{
this._database = database;
this.UserRepository = userRepository;
this.PeopleRepository = peopleRepository;
}
protected IDatabase Database
{
get { return _database; }
}
...snip...
}
User Service Layer Implementation Constructor:
public class UserServices : BaseServices, IUserServices
{
private IUnitOfWork _uow;
public UserServices(IUnitOfWork uow)
: base(uow)
{
_uow = uow;
}
...snip...
}
User Repository Constructor:
public class UserRepository : RepositoryBase<User>, IUserRepository
{
public UserRepository(IDatabase database)
: base(database)
{
}
...snip...
}
Controller Constructor:
public IUserServices _userServices { get; set; }
public ActivityController(IUserServices userServices)
{
_userServices = userServices;
}
}
Using Ninject 3.0.0 you can use WhenAnyAncestrorNamed("Some name") But if you need to run asyncronous things you should thing about splitting your application into a web frontend and a server backend. This could make many things easier.

Unit testing custom MembershipProvider.ValidateUser, using code in Global.asax

I have a unit test to check my AccountController.LogIn method. A redirect result is returned to indicate successs, otherwise a viewresult is returned.
The test always fails as the return type is always viewresult, even though the test should return success as the credentials are valid, however I can't identify where the problem is.
My TestMethod:
CustomerRepositoryTest.cs
[TestMethod]
public void Can_Login_With_Valid_Credentials()
{
// Arrange
Mock<IAddressRepository> mockAddressRepository = new Mock<IAddressRepository>();
Mock<ICustomerRepository> mockCustomerRepository = new Mock<ICustomerRepository>();
Mock<IOrderRepository> mockOrderRepository = new Mock<IOrderRepository>();
LoginViewModel model = new LoginViewModel
{
Email = "me#5.com",
Password = "password"
};
AccountController target = new AccountController(mockCustomerRepository.Object, mockAddressRepository.Object, mockOrderRepository.Object);
// Act
ActionResult result = target.LogIn(model);
// Assert
Assert.IsInstanceOfType(result, typeof(RedirectResult));
Assert.AreEqual("", ((RedirectResult)result).Url);
}
When I run the test, it fails in My AccountController Login method when I call ValidateUser
AccountController.cs
if (Membership.ValidateUser(LoginModel.Email, LoginModel.Password))
{
...
return RedirectToRoute(new
{
controller = "Account",
action = "Details"
});
}
else
{
return View();
}
My custom MembershipProvider ValidateUser looks like this:
AccountMembershipProvider.cs
public class AccountMembershipProvider : MembershipProvider
{
[Inject]
public ICustomerRepository repository { get; set; }
public override bool ValidateUser(string username, string password)
{
var cust = repository.GetAllCustomers().SingleOrDefault..
When I run the application normally i.e. not testing, the login works fine. In the application I inject the CustomerRepository into the custom membership provider in Global.asax:
public class MvcApplication : System.Web.HttpApplication
{
private IKernel _kernel = new StandardKernel(new MyNinjectModules());
internal class MyNinjectModules : NinjectModule
{
public override void Load()
{
Bind<ICustomerRepository>().To<CustomerRepository>();
}
}
protected void Application_Start()
{
_kernel.Inject(Membership.Provider);
...
Is it the case that the Global.asax code isn't run while unit testing? and so my custom provider isn't being injected, hence the fail?
UPDATE
I mocked my Provider class and passed the mocked CustomerRepository object to it.
Mock<AccountMembershipProvider> provider = new Mock<AccountMembershipProvider>();
provider.Object.repository = mockCustomerRepository.Object;
I then created a setup for the method I'm trying to test:
mockCustomerRepository.Setup(m => m.IsValidLogin("me#5.com", "password")).Returns(true);
But unfortunately I'm still getting a fail every time. To answer the question about whether I need a real or mocked object for the test - I'm not fussy, I just want to get it working at the moment!
UPDATE 2
I made those changes, and while it's still failing, it has allowed me to identify the specific problem. While debugging the test, I discovered that when I call the overridden
Membership.ValidateUser(LoginModel.Email, LoginModel.Password)
The Membership.Provider is of type SqlMembershipProvider (which is presumably the default type) and consequently validation fails.
If I cast the provider to my custom provider...
((AccountMembershipProvider)Membership.Provider).ValidateUser(LoginModel.Email, LoginModel.Password)
I get an InvalidCastException when running the test. So it seems that my mocked AccountMembershipProvider isn't being used for the test and instead the default provider is being used.
I think you have identified this already in the comment:
// set your mock provider in your AccountController
However I'm not sure what you mean exactly - I don't have a property on my AccountController to assign the provider to, and i'm not injecting it into the constructor.
Your original question:
"Is it the case that the Global.asax code isn't run while unit testing? and so my custom provider isn't being injected, hence the fail?"
My answer:
Yes.
The global.asax file is used by ASP.Net and ISS at run-time. It is compiled when the server receives it's first request.
When you are testing, you aren't in the context of a ASP.Net web-application running in ISS, but rather in program running in a test session. This means your global.asax won't get called.
More importantly, when you call:
Mock<ICustomerRepository> mockCustomerRepository = new Mock<ICustomerRepository>();
Ninject won't get called the fill the import. Moq will create a mock based on the interface. No real object will be created.
Since you did not define any Setup methods, ie:
mockCustomerRepository.Setup(mock => mock.MyAuthenticateMethod()).Returns(true);
You are passing around a mock with no defined behaviour. By default these will return false. Which probably explains why you are always getting a viewresult.
What you need to do is define setup methods for the methods you need to mock.
These are the methods of CustomerRepository that will get called you when call:
target.LogIn(model);
Also note that your AccountMembershipProvider won't get it's CustomerRepository injected since NInject won't be used. If you are testing the AccountController and it's not static (Moq doesn't work with static) you should consider mocking the AccountMembershipProvider. If you can't, then you would need to supply your mocked instance of CustomerRepository to AccountMembershipProvider.repository in your tests.
Another solution, instead of creating a Moq mock, you could also manually create (with new) a real instance of CustomerRepository in your test.
You could have Ninject do it, but at this point why? You can create it yourself and you know what specific type to create.
It all boils down to if you need a mock or a real instance of the object for this test.
Update:
If your provider is mocked, there is no need to set the repository on it. When you are calling a mock, the real object won't get called.
What you need to do is something like this:
Mock<AccountMembershipProvider> provider = new Mock<AccountMembershipProvider>();
// set your mock provider in your AccountController
provider.Setup(m => m.ValidateUser("me#5.com", "password")).Returns(true);
Update 2:
I think you are pretty close to making your test work. Without seeing all of your code (test and class under test) I can't really give you anymore help. I also feel I answered your original question, but if you are still stuck you might get more help by asking a new question relating to the problem you are currently tackling.
In your code you only create controller, but not run initialization for membership. I recommend you to create your own UserService with method ValidateUser and other you need instead of static class Membership usage.

Resources