How to test a Ninject Factory returns the same instance in RequestScope - unit-testing

In a WebApi application, I am using Ninject to inject a factory that allows consuming classes to create a DbContext that is scoped according to their requirements. I want to be able to write a unit test that verifies that two calls to the same factory for a Request scoped context return the same instance.
The factory interface is:
public interface IContextFactory
{
IMyContext GetContext();
IMyContext GetTransientContext();
}
The Ninject configuration looks like this:
Bind<IContextFactory>().ToFactory();
Bind<IMyContext>().To<MyContext>()
.InRequestScope()
.NamedLikeFactoryMethod((IContextFactory f) => f.GetContext());
Bind<IMyContext>().To<MyContext>()
.InTransientScope()
.NamedLikeFactoryMethod((IContextFactory f) => f.GetTransientContext());
My unit test is as follows:
[Fact]
public void RequestScopedContextAlwaysSame()
{
// Arrange
NinjectWebCommon.Start();
var factory = (IContextFactory)NinjectWebCommon.Bootstrapper.Kernel.GetService(typeof(IContextFactory));
//Act
var context1 = factory.GetContext();
var context2 = factory.GetContext();
//Assert
Assert.Same(context1, context2);
}
I expected the both calls to the factory to return the same instance, but in fact they are two different instances. I think this is a testing error as in the application, I have been able to successfully verify that the same instance is injected into different consumers when they call the GetContext() method.
I suspect this is not working in a unit test because there is no HttpContext and InRequestScope() depends on it. Is there a way round this?

I suspect this is not working in a unit test because there is no
HttpContext and InRequestScope() depends on it.
I think you are right. You may try :
Bind<IMyContext>().To<MyContext>()
.InScope(ctx => this.Scope)
.NamedLikeFactoryMethod((IContextFactory f) => f.GetContext());
where this.Scope is a property of your Test class (any reference type will be ok) the value of which is initialized upon your test setup
Alternatively, if you still want to use the InRequestScope syntax, you may try :
public class MyPlugin : INinjectHttpApplicationPlugin
{
private Object Scope { get; } = true;
public void Dispose(){}
public INinjectSettings Settings { get; set; }
public object GetRequestScope(IContext context)
{
return Scope;
}
public void Start() { }
public void Stop() { }
}
Then your test would be something like :
public void RequestScopedContextAlwaysSame()
{
var kernel = new StandardKernel();
kernel.Components.Add<INinjectHttpApplicationPlugin, MyPlugin>();
kernel.Bind<IContextFactory>().ToFactory();
kernel.Bind<IMyContext>().To<MyContext>()
.InRequestScope()
.NamedLikeFactoryMethod((IContextFactory f) => f.GetContext());
kernel.Bind<IMyContext>().To<MyContext>()
.InTransientScope()
.NamedLikeFactoryMethod((IContextFactory f) => f.GetTransientContext());
var factory = kernel.Get<IContextFactory>();
//Act
var context1 = factory.GetContext();
var context2 = factory.GetContext();
//Assert
Assert.IsTrue(context1.Equals(context2));
}

Related

Can we add a Program.cs or any code able to immediately set a ServiceProvider into a Unit Test project? [duplicate]

I am working on an ASP.Net Core MVC Web application.
My Solution contains 2 projects:
One for the application and
A second project, dedicated to unit tests (XUnit).
I have added a reference to the application project in the Tests project.
What I want to do now is to write a class in the XUnit Tests project which will communicate with the database through entity framework.
What I was doing in my application project was to access to my DbContext class through constructor dependency injection.
But I cannot do this in my tests project, because I have no Startup.cs file. In this file I can declare which services will be available.
So what can I do to get a reference to an instance of my DbContext in the test class?
You can implement your own service provider to resolve DbContext.
public class DbFixture
{
public DbFixture()
{
var serviceCollection = new ServiceCollection();
serviceCollection
.AddDbContext<SomeContext>(options => options.UseSqlServer("connection string"),
ServiceLifetime.Transient);
ServiceProvider = serviceCollection.BuildServiceProvider();
}
public ServiceProvider ServiceProvider { get; private set; }
}
public class UnitTest1 : IClassFixture<DbFixture>
{
private ServiceProvider _serviceProvider;
public UnitTest1(DbFixture fixture)
{
_serviceProvider = fixture.ServiceProvider;
}
[Fact]
public void Test1()
{
using (var context = _serviceProvider.GetService<SomeContext>())
{
}
}
}
But bear in your mind using EF inside a unit test is not a good idea and it's better to mock DbContext.
The Anatomy of Good Unit Testing
You can use Xunit.DependencyInjection
For unit tests you need to mock your context.
There is a great nuget package for mocking that is called Moq.
Some help to get you started:
public ClassName : IDisposable
{
private SomeClassRepository _repository;
private Mock<DbSet<SomeClass>> _mockSomeClass;
public ClassName()
{
_mockSomeClass = new Mock<DbSet<SomeClass>>();
var mockContext = new Mock<IApplicationDbContext>();
mockContext.SetupGet(c => c.SomeClass).Returns(_mockSomeClass.Object);
_repository = new SomeClassRepository(mockContext.Object);
}
public void Dispose()
{
// Anything you need to dispose
}
[Fact]
public void SomeClassTest()
{
var someClass = new SomeClass() { // Initilize object };
_mockSomeClass.SetSource(new[] { someClass });
var result = _repository.GetSomethingFromRepo( ... );
// Assert the result
}
}
For integration tests you do the same thing but the setup is:
_context = new ApplicationDbContext();
Make sure that your TestClass inherits from IDisposable (TestClass : IDisposable) so that you can dispose the context after each test.
https://xunit.github.io/docs/shared-context
You can to use package Microsoft.EntityFrameworkCore.InMemory
var _dbContextOptions = new DbContextOptionsBuilder<DbContext>().UseInMemoryDatabase(Guid.NewGuid().ToString()).Options;
And then
var context = new DbContext(_dbContextOptions);

Why "getSharedPreferences" return null in unit testing?

My classes is written in Kotlin and here is my SharedPreferenceHandler
class SharedPreferenceHandler(sharedPrefs: SharedPreferences) {
companion object {
var mInstance: SharedPreferenceHandler = SharedPreferenceHandler(getPrefs())
private fun getPrefs(): SharedPreferences {
return Application.mInstance.getSharedPreferences(
"myApp", Context.MODE_PRIVATE)
}
fun getInstance(): SharedPreferenceHandler {
return mInstance
}
}
private var sharedPreferences = sharedPrefs
var accessToken: String?
get() = sharedPreferences.getString(SharedPreference.ACCESS_TOKEN.name, null)
set(token) = sharedPreferences.edit().putString(SharedPreference.ACCESS_TOKEN.name, token).apply()
}
Here is method called in presenter:
override fun reload(vm: ViewModel) {
super.updateViewModel(vm) {
//some stuffs
}
}
Here is my test method:
#Test
public void reload() {
when(SharedPreferenceHandler.Companion.getMInstance().getAccessToken()).thenReturn("234234234234234");
presenter.reload(viewModel);
}
In handler from super.updateViewModel(vm) I call "SharedPreferenceHandler.mInstance.accessToken!!)"
That is what is thrown:
Caused by: java.lang.IllegalStateException:
Application.mInstanc…m", Context.MODE_PRIVATE) must not be null
at
com.zuum.zuumapp.preferences.SharedPreferenceHandler$Companion.getPrefs(SharedPreferenceHandler.kt:18)
at
com.zuum.zuumapp.preferences.SharedPreferenceHandler$Companion.access$getPrefs(SharedPreferenceHandler.kt:14)
at
com.zuum.zuumapp.preferences.SharedPreferenceHandler.(SharedPreferenceHandler.kt:15)
I wanna to get accessToken by calling " SharedPreferenceHandler.mInstance.accessToken!!" in my test class.
Is possible to get that in my test method?
You can't use Android SharedPreferences in unit test, but you can mock your method call by this:
Mockito.`when`(SharedPreferenceHandler.mInstance.accessToken).thenReturn("token")
And return what you need.
You should not test your code this way. You should create an interface for class you want to mock:
interface MySharedPreferences {
fun getAccessToken(): String
}
Let your SharedPreferencesHandler implements this interface. Then in your presenter (or other class you want to test) inject dependencies (f.e. by constructor or framework like Dagger/Kodein) into your object. Then there is possibility to easy mock this interface. I assume in #Before you create class you test - and then just pass as param your mocked SharedPreferencesHandler.
Testing things with static dependencies is possible, but is but tricky (and a lot of people consider static dependencies as anti-pattern). How to do it is described here: How to android unit test and mock a static method
Example:
class MyPresenter(val sp: MySharedPreferences) {
/* some code here */
fun validateToken() {
if (sp.getAccessToken() == "") throw new Exception()
}
}
Like you see sp is injected into this class as parameter. Normally you don't create views/presenters etc. directly in code but by DI framework (like Dagger or Kodein). Anyway, static dependencies are not easy testable. Injected interface-dependencies can be mocked, and you operating not on object, but on behaviors (so it's bigger level of abstraction). So, now in your test all you have to do is:
class MyTest() {
#Mock lateinit var sharedPreferencesMock: MySharedPreferences
lateinit var instance: MyPresenter
#Before
fun setUp() {
instance = MyPresenter(sharedPreferencesMock)
}
#Test
fun testSomething() {
`when`(sharedPreferencesMock.getAccessToken()).thenReturn("myAccessToken")
/* here is your test body */
}
}

How to use Moq to Prove that the Method under test Calls another Method

I am working on a unit test of an instance method. The method happens to be an ASP.NET MVC 4 controller action, but I don't think that really matters much. We just found a bug in this method, and I'd like to use TDD to fix the bug and make sure it doesn't come back.
The method under test calls a service which returns an object. It then calls an internal method passing a string property of this object. The bug is that under some circumstances, the service returns null, causing the method under test to throw a NullReferenceException.
The controller uses dependency injection, so I have been able to mock the service client to have it return a null object. The problem is that I want to change the method under test so that when the service returns null, the internal method should be called with a default string value.
The only way I could think to do this is to use a mock for the class under test. I want to be able to assert, or Verify that this internal method has been called with the correct default value. When I try this, I get a MockException stating that the invocation was not performed on the mock. Yet I was able to debug the code and see the internal method being called, with the correct parameters.
What's the right way to prove that the method under test calls another method passing a particular parameter value?
I think there's a code smell here. The first question I'll ask myself in such a situation is, is the "internal" method really internal/ private to the controller under test. Is it the controller's responsibility to do the "internal" task? Should the controller change when the internal method's implementation changes? May be not.
In that case, I would pull out a new targeted class, which has a public method which does the stuff which was until now internal to the controller.
With this refactoring in place, I would use the callback mechanism of MOQ and assert the argument value.
So eventually, you will end up mocking two dependancies:
1. The external service
2. The new targeted class which has the controller's internal implementation
Now your controller is completely isolated and can be unit tested independently. Also, the "internal" implementation becomes unit testable and should have its own set of unit tests too.
So your code and test would look something like this:
public class ControllerUnderTest
{
private IExternalService Service { get; set; }
private NewFocusedClass NewFocusedClass { get; set; }
const string DefaultValue = "DefaultValue";
public ControllerUnderTest(IExternalService service, NewFocusedClass newFocusedClass)
{
Service = service;
NewFocusedClass = newFocusedClass;
}
public void MethodUnderTest()
{
var returnedValue = Service.ExternalMethod();
string valueToBePassed;
if (returnedValue == null)
{
valueToBePassed = DefaultValue;
}
else
{
valueToBePassed = returnedValue.StringProperty;
}
NewFocusedClass.FocusedBehvaior(valueToBePassed);
}
}
public interface IExternalService
{
ReturnClass ExternalMethod();
}
public class NewFocusedClass
{
public virtual void FocusedBehvaior(string param)
{
}
}
public class ReturnClass
{
public string StringProperty { get; set; }
}
[TestClass]
public class ControllerTests
{
[TestMethod]
public void TestMethod()
{
//Given
var mockService = new Mock<IExternalService>();
mockService.Setup(s => s.ExternalMethod()).Returns((ReturnClass)null);
var mockFocusedClass = new Mock<NewFocusedClass>();
var actualParam = string.Empty;
mockFocusedClass.Setup(x => x.FocusedBehvaior(It.IsAny<string>())).Callback<string>(param => actualParam = param);
//when
var controller = new ControllerUnderTest(mockService.Object, mockFocusedClass.Object);
controller.MethodUnderTest();
//then
Assert.AreEqual("DefaultValue", actualParam);
}
}
Edit: Based on the suggestion in the comments to use "verify" instead of callback.
Easier way to verify the parameter value is by using strict MOQ behavior and a verify call on the mock after system under test is executed.
Modified test could look like below:
[TestMethod]
public void TestMethod()
{
//Given
var mockService = new Mock<IExternalService>();
mockService.Setup(s => s.ExternalMethod()).Returns((ReturnClass)null);
var mockFocusedClass = new Mock<NewFocusedClass>(MockBehavior.Strict);
mockFocusedClass.Setup(x => x.FocusedBehvaior(It.Is<string>(s => s == "DefaultValue")));
//When
var controller = new ControllerUnderTest(mockService.Object, mockFocusedClass.Object);
controller.MethodUnderTest();
//Then
mockFocusedClass.Verify();
}
"The only way I could think to do this is to use a mock for the class under test."
I think you should not mock class under test. Mock only external dependencies your class under test has. What you could do is to create a testable-class. It would be a class which derives from your CUT and here you can catch the calls to the another method and verify it's parameter later. HTH
Testable class in the example is named MyTestableController
Another method is named InternalMethod.
Short example:
[TestClass]
public class Tests
{
[TestMethod]
public void MethodUnderTest_WhenServiceReturnsNull_CallsInternalMethodWithDefault()
{
// Arrange
Mock<IService> serviceStub = new Mock<IService>();
serviceStub.Setup(s => s.ServiceCall()).Returns((ReturnedFromService)null);
MyTestableController testedController = new MyTestableController(serviceStub.Object)
{
FakeInternalMethod = true
};
// Act
testedController.MethodUnderTest();
// Assert
Assert.AreEqual(testedController.SomeDefaultValue, testedController.FakeInternalMethodWasCalledWithThisParameter);
}
private class MyTestableController
: MyController
{
public bool FakeInternalMethod { get; set; }
public string FakeInternalMethodWasCalledWithThisParameter { get; set; }
public MyTestableController(IService service)
: base(service)
{ }
internal override void InternalMethod(string someProperty)
{
if (FakeInternalMethod)
FakeInternalMethodWasCalledWithThisParameter = someProperty;
else
base.InternalMethod(someProperty);
}
}
}
The CUT could look something like this:
public class MyController : Controller
{
private readonly IService _service;
public MyController(IService service)
{
_service = service;
}
public virtual string SomeDefaultValue { get { return "SomeDefaultValue"; }}
public EmptyResult MethodUnderTest()
{
// We just found a bug in this method ...
// The method under test calls a service which returns an object.
ReturnedFromService fromService = _service.ServiceCall();
// It then calls an internal method passing a string property of this object
string someStringProperty = fromService == null
? SomeDefaultValue
: fromService.SomeProperty;
InternalMethod(someStringProperty);
return new EmptyResult();
}
internal virtual void InternalMethod(string someProperty)
{
throw new NotImplementedException();
}
}

Unittest SignalR Hubs

I Would like to test my Hub in SignalR, what is the best approach?
Possible solutions I have thought about so far:
Create a testable Hub
Abstract logic to separate class
Selenium (would like to test smaller units)
Or is it some SignalR testing features have overlooked
Currently using SignalR 0.4, and NUnit as the testing framework.
This link shows how to unit test SignalR hub methods using Moq. You mock up the respository, clients, context, and the caller. Here's the code from the site, I made some minor changes to make it work with the latest SignalR:
public class TestableChatHub : ChatHub
{
public Mock<IChatRepository> MockChatRepository { get; private set; }
public TestableChatHub(Mock<IChatRepository> mockChatRepository)
: base(mockChatRepository.Object)
{
const string connectionId = "1234";
const string hubName = "Chat";
var mockConnection = new Mock<IConnection>();
var mockUser = new Mock<IPrincipal>();
var mockCookies = new Mock<IRequestCookieCollection>();
var mockRequest = new Mock<IRequest>();
mockRequest.Setup(r => r.User).Returns(mockUser.Object);
mockRequest.Setup(r => r.Cookies).Returns(mockCookies.Object);
Clients = new ClientProxy(mockConnection.Object, hubName);
Context = new HubCallerContext(mockRequest.Object, connectionId);
var trackingDictionary = new TrackingDictionary();
Caller = new StatefulSignalProxy(
mockConnection.Object, connectionId, hubName, trackingDictionary);
}
}
Then the site shows that you can use this testable hub to write unit tests:
[TestClass]
public class ChatHubTests
{
private TestableChatHub _hub;
public void SetUpTests()
{
_hub = GetTestableChatHub();
}
[Test]
public void ExampleTest()
{
SetUpTests();
const string message = "test";
const string connectionId = "1234";
var result = _hub.Send(message);
_hub.MockChatRepository.Verify(r => r.SaveMessage(message, connectionId));
Assert.IsTrue(result);
}
private TestableChatHub GetTestableChatHub()
{
var mockRepository = new Mock<IChatRepository>();
mockRepository.Setup(m => m.SaveMessage(
It.IsAny<string>(), It.IsAny<string())).Returns(true);
return new TestableChatHub(mockRepository);
}
}
It's quite simple to create to unit test SignalR hubs using a couple of neat tricks. One thing to note is that SignalR uses dynamic classes which might not be supported by your mocking framework (I use NSubstitute).
public class ProjectsHub: Hub
{
public void AddProject(string id)
{
Clients.All.AddProject(id);
}
}
[TestFixture]
public class ProjectsHubTests
{
// Operations that clients might receive
// This interface is in place in order to mock the
// dynamic object used in SignalR
public interface ISignals
{
void AddProject(string id);
}
[Test]
public void AddProject_Broadcasts()
{
// Arrange
ProjectsHub hub = new ProjectsHub();
IHubCallerConnectionContext clients =
Substitute.For<IHubCallerConnectionContext>();
ISignals signals = Substitute.For<ISignals>();
SubstituteExtensions.Returns(clients.All, signals);
hub.Clients = clients;
// Act
hub.AddProject("id");
// Assert
signals.Received(1).AddProject("id");
}
}
Rewriting this to use e.g. Moq should be pretty simple.
This question is from a while ago, but I'll do my best to answer anyway.
If you have a lot of logic in your actual hub class, it would certainly make sense to abstract the logic to a separate class. I did the same for my SignalR-powered multiplayer demo. The only behaviour that should go in your hub class itself is the one related to messaging. All further action should be delegated.
Note: This is very much like the guidelines for controller design in ASP .NET MVC: Keep your controllers small and delegate the real work.
If you want integration tests with SignalR actually doing some work, selenium webdriver would be a good option. But you will probably need to do some tweaking to get the SignalR messaging working perfectly in the context of the tests. Do a google search for "signalr selenium" (without the quotes) to get started on the right track.
Some blogposts about automated tests for SignalR => here and here
With the SignalR 2.0 you can do it this way:
// Arrange
var hub = new CodeInteractivePreviewHub();
var mockClients = new Mock<IHubCallerConnectionContext<dynamic>>();
hub.Clients = mockClients.Object;
dynamic all = new ExpandoObject();
mockClients.Setup(m => m.All).Returns((ExpandoObject)all);
// Act
var allSourceCodes = hub.InitiateCommunication(); //Change this line to your Hub's method
// Assert
Assert.IsNotNull(allSourceCodes);
This is modified version of Iarsm's answer, to work with XUnit and MOQ.
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
using Moq;
using Xunit;
namespace TestLibrary {
public class ProjectsHub : Hub {
public void AddProject(string id) {
Clients.All.AddProject(id);
}
}
public class ProjectsHubTests {
// Operations that clients might receive
// This interface is in place in order to mock the
// dynamic object used in SignalR
public interface ISignals {
void AddProject(string id);
}
[Fact]
public void AddProject_Broadcasts() {
// Arrange
ProjectsHub hub = new ProjectsHub();
var clients = new Mock<IHubCallerConnectionContext<dynamic>>();
var signals = new Mock<ISignals>();
hub.Clients = clients.Object;
signals.Setup(m => m.AddProject(It.Is<string>(s => s == "id"))).Verifiable();
clients.Setup(m => m.All).Returns(signals.Object);
// Act
hub.AddProject("id");
// Assert
signals.VerifyAll();
}
}
}
My interface was out of the test project, but here's how I did it using NUnit and Moq.
using Microsoft.AspNetCore.SignalR;
using Moq;
using NUnit.Framework;
namespace TestLibrary
{
// Operations that clients might receive
// This interface is in place in order to mock the
// dynamic object used in SignalR
public interface ISignals
{
void AddProject(string id);
}
public class ProjectsHub : Hub<ISignals>
{
public void AddProject(string id)
{
Clients.All.AddProject(id);
}
}
public class ProjectsHubTests
{
[Test]
public void AddProject_Broadcasts()
{
// Arrange
ProjectsHub hub = new ProjectsHub();
var clients = new Mock<IHubCallerClients<ISignals>>();
var signals = new Mock<ISignals>();
hub.Clients = clients.Object;
signals.Setup(m => m.AddProject(It.Is<string>(s => s == "id"))).Verifiable();
clients.Setup(m => m.All).Returns(signals.Object);
// Act
hub.AddProject("id");
// Assert
signals.VerifyAll();
}
}
}

Moq - how to verify method call which parameter has been cleaned (a list)

I've got the following code and I need help to write a unit test for it. I'm using Moq library.
Here's the deal. I have a business class with a dependency to a repository (interface), so I can use it to save my entities to the database. My entity is basically a list of strings. The method AddAndSave, from MyBusinessClass, grab the value it receives as a parameters, put it into the list and call Save method from IRepository. Then, I clear the list of my entity. The code below show this example (I've made it simple so I can explain it here).
There's a unit test, too.
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
namespace TestesGerais
{
public class MyEntity
{
public MyEntity()
{
MyList = new List<string>();
}
public List<string> MyList { get; set; }
}
public interface IRepository
{
void Save(MyEntity entity);
}
public class MyBusinessClass
{
public IRepository Repository { get; set; }
private MyEntity _entity = new MyEntity();
public void AddAndSave(string info)
{
_entity.MyList.Add(info);
Repository.Save(_entity);
_entity.MyList.Clear(); // for some reason I need to clear it
}
}
[TestClass]
public class UnitTest10
{
[TestMethod]
public void TestMethod1()
{
var mock = new Mock<IRepository>();
MyBusinessClass b = new MyBusinessClass() { Repository = mock.Object };
b.AddAndSave("xpto");
mock.Verify(m => m.Save(It.Is<MyEntity>(x => x.MyList[0] == "xpto")), Times.Exactly(1));
}
}
}
My unit-test check if the IRepository's Save method was called with its parameter (an entity) having one element in the list, and having the value "xpto" in this element.
When I run this test, it turns red with the error message "Test method TestesGerais.UnitTest10.TestMethod1 threw exception:
System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index".
Ok, this is caused by the list that has been cleaned. If I comment the line "_entity.MyList.Clear();", everything goes well.
My question is: how can I test this without commenting the "Clear" line in my business class, and making sure that my repository's method is called passing the specific value (entity with one element with value "xpto")?
Thanks
I've changed my unit test using the Callback feature of Moq. This way, I can setup the mock so when AddAndSave is called, the parameter it receives is saved into a variable from my unit test, and I can assert it later.
[TestMethod]
public void TestMethod1()
{
var mock = new Mock<IRepository>();
string result = string.Empty;
mock.Setup(m => m.Save(It.IsAny<MyEntity>())).Callback((MyEntity e) => { result = e.MyList[0]; });
MyBusinessClass b = new MyBusinessClass() { Repository = mock.Object };
b.AddAndSave("xpto");
Assert.AreEqual(result, "xpto");
}
You could split your method up a bit. "AddAndSave" isn't all it does. You could then just test the behaviour of the adding and saving bit in isolation.