I have use Cosmosdb Container its abstract class.
I need xUnit test case with mock using Moq library
public class SmsTemplateRepository : ISmsTemplateRepository
{
private Container _container;
public SmsTemplateRepository(CosmosClient dbClient, string databaseName, string containerName)
{
_container = dbClient.GetContainer(databaseName, containerName);
}
public IEnumerable<SmsTemplate> GetAll()
{
return _container.GetItemLinqQueryable<SmsTemplate>(true);
}
**public async Task InsertAsync(SmsTemplate smsTemplate)
{
await _container.CreateItemAsync(smsTemplate);
}**
}
You have to mock the whole chain from the dependency you pass into the constructor of the repository.
Create a list of templates you want to simulate GetAll to return:
var smsTemplates = new[]
{
new SmsTemplate { Name = "Name1" },
new SmsTemplate { Name = "Name3" }
}.AsQueryable()
.OrderBy(x => x.Name);
Create a mocked CosmosClient and a mocked Container and setup the CosmosClient mock to return the mocked container:
var container = new Mock<Container>();
var client = new Mock<CosmosClient>();
client.Setup(x => x.GetContainer(It.IsAny<string>(), It.IsAny<string>())
.Returns(container.Object);
Setup the mocked container to return the template list and pass in the mocked CosmosClient to the constructor of the repository:
container.Setup(x => x.GetItemLinqQueryable<SmsTemplate>(It.IsAny<bool>())
.Returns(smsTemplates);
var repository = new SmsTemplateRepository(client.Object, ....);
GetAll will now return the smsTemplates
Related
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);
I have a dotnet 3.1 core web api application and looking to use xUnit. In this, I am only wanting to test the public methods, BUT I do have several private methods that either make a call to a database to return data or make a rest call to an external service.
Question:
I am NOT trying to test the private method, but how can I fake the return data of the private methods, so that when my public method calls the private method, I can return a fake set of data so that my public method and calculations can be tested?
Thanks in advance!
Update
Here is an example of what I am trying to do.
public class FooRepository{
public MyObject CalculateValues{
var myReturnObject = new MyObject();
var crewSalaries = GetCrewSalaries(myCrew)
myObject.TotalSalary = crewSalaries.Sum(x=>x.salary)
// Insert other calculations here
}
private MyObject GetCrewSalaries(List<Crew> myCrew){
return dbContext.Where(x=>x.id == myCrew.id).ToList();
}
}
Public Class FooRepositoryTest{
[Fact]
public Test1()
{
var fooClass = new fooClass();
// mock or hijack fooClass.GetCrewSalaries, so that I can return fake data
var result = fooClass.CalculateValues();
// assert statement here
}
private GetFakeSalaryData()
{
return new List<CrewSalaries>{
[
id:1,
salary:23
],
[
id:2,
salary:23.1
],
}
}
}
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));
}
i am new to unittesting with rhino mocks and i am confused how to mock my dependency which are initialized in controller constructor using unity container.
as per the below code i have to unittest "GetHelloWorld" method with two dependency TestRepository and RedisCacheManager .
public class TestController : BaseController
{
private ITestRepository testRepo;
private IRedisCacheManager cacheManager;
public TestController()
{
testRepo = UnityResolver.Resolve<ITestRepository>();
cacheManager = UnityResolver.Resolve<IRedisCacheManager>();
}
public ActionResult GetHelloWorld()
{
LoggerHelper.WriteInfo("Inside GetHelloWorld Method..");
testRepo.PutDataInCustomAzureDB();
cacheManager.Add("Test", "TestData", new TimeSpan(0, 1, 0));
var getData = cacheManager.Get<string>("Test");
cacheManager.Add("Test", "TestData123", new TimeSpan(0, 1, 0));
var getDataa = cacheManager.Get<string>("Test");
LoggerHelper.WriteInfo("Leaving GetHelloWorld Method..");
return null;
}
}
}
You have to have a separate UnityResolver for the unit test project and there you have to send mock objects in the Resolve method. That is have a separate container for the unit test project and then
Mock<IRedisCacheManager> _mockRedis = new Mock<IRedisCacheManager>();
container.RegisterInstance <IRedisCacheManager>(_mockRedis.Object);
Another way of doing this would be to inject the resolver or the dependencies in the class itself
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();
}
}
}