Writing unit test cases for Sitecore project - sitecore

My client wants to have 100% code coverage for all the projects. I have written few test cases very long back for Web API's using nUnit. But my client decided to use xUnit as a unit test framework using Moq as Mock framework.
As i have never worked on unit test case for sitecore project, could anyone please en-light us on the approach? As a start coudl anyone please write a sample test case for the below method? We are using GlassMapperFramework as a ORM.
public class RegistrationController : GlassController
{
public ActionResult RegistrationInitiation()
{
var someobject = GetDataSourceItem<IRegistrationMainContent>();
return View(someobject);
}
}

To test your Controllers, you will want to inject the Sitecore Context into the Controller. The GlassController has an overload method on it GlassController(ISitecoreContext). This is used to Unit Test your controllers. It also has other overloads if needed...
Here is more complete code you need to unit test the controller
private Mock<IRegistrationModel> RegistrationModel { get; set; };
private RegistrationController Controller { get; set; }
[TestInitialize]
public void Setup()
{
var mockSitecoreContext = new Mock<ISitecoreContext>();
this.RegistrationModel = new Mock<IRegistrationModel>();
this.RegistrationModel.SetupAllProperties();
mockSitecoreContext.Setup(sc =>sc.GetItem<IRegistrationModel
(It.IsAny<string>(), false, false)).
Returns(this.RegistrationModel.Object);
this.Controller = new RegistrationController {SitecoreContext =
mockSitecoreContext.Object }
}
[TestMethod]
public void Your_Unit_Test_Name()
{
//....perform unit test here
this.Controller.SitecoreContext = null;
var result = this.Controller.GetIndex() as ViewResult;
//Assert ....
}
Let me know if you have questions!

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);

unit testing umbraco 7.12 controller

i've setup a unit test project for my umbraco 7.12 installation with Our.Umbraco.Community.Tests nuget installed as well as nunit, nunit 3 test adapter and NUnitV2Driver. i have a unit test where i'm inheriting from BaseRoutingTest (from the umbraco community tests nuget) that nunit just doesn't seem to want to run:
using System;
using System.Globalization;
using System.Web.Routing;
using System.Web.Security;
using Moq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Dictionary;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Profiling;
using Umbraco.Tests.TestHelpers;
using Umbraco.Web;
using Umbraco.Web.Mvc;
using Umbraco.Web.Security;
using umbraco7._12test.Models;
using Assert = NUnit.Framework.Assert;
namespace UnitTestProject1
{
[TestFixture]
public class UnitTest1:BaseRoutingTest
{
protected UmbracoContext UmbracoContext { get; set; }
protected UmbracoHelper UmbracoHelper { get; set; }
protected IPublishedContent Content { get; set; }
protected RouteData RouteData { get; set; }
[SetUp]
public override void Initialize()
{
base.Initialize();
SettingsForTests.ConfigureSettings(SettingsForTests.GenerateMockSettings());
this.RouteData = new RouteData();
var routingContext = this.GetRoutingContext(
"http://localhost",
-1,
this.RouteData,
true,
UmbracoConfig.For.UmbracoSettings());
this.UmbracoContext = routingContext.UmbracoContext;
this.Content = Mock.Of<IPublishedContent>();
this.UmbracoContext.PublishedContentRequest = new Umbraco.Web.Routing.PublishedContentRequest(
new Uri("http://localhost"),
routingContext,
UmbracoConfig.For.UmbracoSettings().WebRouting,
s => new string[0])
{
PublishedContent = this.Content,
Culture = new CultureInfo("en-GB")
};
var routeDefinition = new RouteDefinition
{
PublishedContentRequest = this.UmbracoContext.PublishedContentRequest
};
this.RouteData.DataTokens.Add(Constants.Web.UmbracoRouteDefinitionDataToken, routeDefinition);
this.UmbracoHelper = new UmbracoHelper(
this.UmbracoContext,
this.Content,
Mock.Of<ITypedPublishedContentQuery>(),
Mock.Of<IDynamicPublishedContentQuery>(),
Mock.Of<ITagQuery>(),
this.ApplicationContext.Services.DataTypeService,
this.UmbracoContext.UrlProvider,
new Mock<ICultureDictionary>().Object,
Mock.Of<IUmbracoComponentRenderer>(),
new MembershipHelper(this.UmbracoContext, Mock.Of<MembershipProvider>(), Mock.Of<RoleProvider>()));
}
[TearDown]
public override void TearDown()
{
this.UmbracoHelper = null;
this.UmbracoContext = null;
this.Content = null;
base.TearDown();
}
[Test]
public void TestMethod1()
{
var apiController = new
umbraco7._12test.Controllers.ApiController(this.UmbracoContext,this.UmbracoHelper);
var result = apiController.EditContact();
var model = (ContactModel)result.Model;
NUnit.Framework.Assert.IsNotNull(model.FirstName);
NUnit.Framework.Assert.IsNotNull(model.LastName);
}
[Test]
public void TestMethod2() {
Assert.AreEqual(1,1);
}
}
}
as soon as i inherit from BaseRoutingTest nunit will no longer run my tests, no errors just a message saying there are no tests found -
[01/10/2018 14:56:32 Informational] NUnit couldn't find any tests in C:\project\umbraco7.12test\UnitTestProject1\bin\Debug\UnitTestProject1.dll
[01/10/2018 14:56:32 Informational] NUnit Adapter 3.10.0.21: Test execution complete
[01/10/2018 14:56:32 Warning] No test matches the given testcase filter `FullyQualifiedName=UnitTestProject1.UnitTest1.TestMethod1` in C:\project\umbraco7.12test\UnitTestProject1\bin\Debug\UnitTestProject1.dll
if i don't inherit from BaseRoutingTest nunit will run tests again. i need to inherit from BaseRoutingTest though, to setup the UmbracoContext and other things that need to be mocked.
does anybody know what the problem might be?
I don't know Umbraco, so I'm answering this from an NUnit perspective only...
You are trying to use the NUnit 3 test adapter to run NUnit V2 tests. You have installed the V2 driver in order to make NUnit 3 run NUnit V2 tests. Right?
Thing is, the NUnit 3 test adapter doesn't support use of extensions. Even if it did, you would have to copy those extensions manually to the location of the adapter and probably also manually edit a .addins file to make it work.
Much simpler is to use the original NUnit Test Adapter, which is for use with V2.

How to unit test a service call in xUnit and nSubstitute

I been trying to figure out how i can unit test service and so far have got nowhere.
I am using xUnit and NSubstitute (as advised by friends), below is the simple test that i want to run (which fails currently).
public class UnitTest1
{
private readonly RallyService _rallyService;
public UnitTest1(RallyService rallyService)
{
_rallyService= rallyService;
}
[Fact]
public void Test1()
{
var result = _rallyService.GetAllRallies();
Assert.Equal(2, result.Count());
}
}
My rally service class makes a simple call to the db to get all Rally entites and returns those:
public class RallyService : IRallyService
{
private readonly RallyDbContext _context;
public RallyService(RallyDbContext context)
{
_context = context;
}
public IEnumerable<Rally> GetAllRallies()
{
return _context.Rallies;
}
}
Any guidance would be appreciated.
Since you use .NET Core, I assume you also use Entity Framework Core. While it was possible to mock most of the operations in the previous EF version, however the EF Core suggests to use in-memory database for unit testing. I.e. you don't need to mock RallyDbContext, hence NSubstitute is not needed for this particular test. You would need NSubstitute to mock the service when testing a controller or application using the service.
Below is your Test1 written using in-memory database.
public class UnitTest1
{
private readonly DbContextOptions<RallyDbContext> _options;
public UnitTest1()
{
// Use GUID for in-memory DB names to prevent any possible name conflicts
_options = new DbContextOptionsBuilder<RallyDbContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString())
.Options;
}
[Fact]
public async Task Test1()
{
using (var context = new RallyDbContext(_options))
{
//Given 2 records in database
await context.AddRangeAsync(new Rally { Name = "rally1" }, new Rally { Name = "rally2" });
await context.SaveChangesAsync();
}
using (var context = new RallyDbContext(_options))
{
//When retrieve all rally records from the database
var service = new RallyService(context);
var rallies = service.GetAllRallies();
//Then records count should be 2
Assert.Equal(2, rallies.Count());
}
}
}
A working test application with this unit test is in my GitHub for your reference. I used SQL Express in the actual app.
I don't think it is standard to have a unit test constructor with a parameter. The unit test runner will new up this class, and unless you are using something that will auto-inject that parameter I think the test will fail to run.
Here is a standard fixture layout:
public class SampleFixture {
[Fact]
public void SampleShouldWork() {
// Arrange stuff we need for the test. This may involved configuring
// some dependencies, and also creating the subject we are testing.
var realOrSubstitutedDependency = new FakeDependency();
realOrSubstitutedDependency.WorkingItemCount = 42;
var subject = new Subject(realOrSubstitutedDependency);
// Act: perform the operation we are testing
var result = subject.DoWork();
// Assert: check the subject's operation worked as expected
Assert.Equal(42, result);
}
[Fact]
public void AnotherTest() { /* ... */ }
}
If you need a common setup between tests, you can use a parameterless constructor and do common initialisation there.
In terms of the specific class you are trying to test, you need to make sure your RallyDbContext is in a known state to repeatably and reliably test. You may want to look up answers specific to testing Entity Framework for more information.

Unit Testing BLL: mock Repository, UnitOfWork, UnitOfWorkFactory

I need a jump start in testing the methods on my Business layer. Consider the Materials BLL object, how can I test the AddNewMaterial method for it?
interface IGenericRepository<TEntity>
{
TEntity Add(TEntity m);
}
public interface IMaterialRepository : IGenericRepository<Material>
{
}
public interface IUnitOfWork
{
IMaterialRepository Materials { get; private set;}
void Save();
}
public interface IUnitOfWorkFactory
{
IUnitOfWork GetUnitOfWOrk();
}
public class MaterialsBLL
{
private readonly IUnitOfWorkFactory _uowFactory;
//uowFactory comes from DI
public MaterialsBLL(IUnitOfWorkFactory uowFactory)
{
_uowFactory = uowFactory;
}
//TODO: test this
public Material AddNewMaterial(Material m)
{
using(var uow = _uowFactory.GetUnitOfWOrk())
{
var result = uow.Materials.Add(m);
uow.Save();
return result;
}
}
I am using Moq, and XUnit, but am very green. In general I want to do this:
Mock the repositories Add method.
Mock the UoW Materials property to return my repository mock.
Mock the UoWFactory to return the UoW mock.
Create the MaterialsBLL giving the mocked UoWFactory to the contstructor.
Verify that the AddNewMaterials calls the repository's Add, and the UoW's Save, etc.
It seems to me that, I maybe should be creating a Fake MaterialRepository, rather than mocking it? Any other advice? Here is a first crack:
[Fact]
public void TestGetMaterialById()
{
var materialList = GetMaterials();
var materialRepositoryMock = new Mock<IMaterialRepository>();
materialRepositoryMock.Setup(repo => repo.Get(4)).Returns(materialList.First());
var uowMock = new Mock<IUnitOfWork>();
uowMock.SetupProperty<IMaterialRepository>(uow => uow.Materials, materialRepositoryMock.Object);
var uowFactoryMock = new Mock<IUnitOfWorkFactory>();
uowFactoryMock.Setup(f => f.GetUnitOfWork()).Returns(uowMock.Object);
var materialsBll = new Materials(uowFactoryMock.Object);
var result = materialsBll.Get(4);
Assert.Equal(result.MaterialId, 4);
Assert.Equal(result.Name, "Four");
}
When you feel like you need several levels of nested mock objects, there's generally something wrong with your design.
The Law of Demeter warns us here that you should probably not tinker with uow.Materials in MaterialsBLL.
Besides, a Unit of Work is typically not the place to expose Repositories. The code that needs to access Materials will usually have a direct reference to an IMaterialsRepository, not ask it from the UoW, and then the Repository implementation might reference the UoW internally.
This leads to a flatter design and simplifies your production code as well as your tests.

Unit test annotation based Spring MVC Portlet controller

I am a newbie learning spring mvc with portlets. I have a controller which returns the view. I am not sure how to write the unit test that controller.
#controller
#RequestMapping("VIEW")
public class HelloController {
#ResourceMapping(value = "hello")
public String helloWorld(RenderRequest request) {
return "hello";
}
and my Unit Test controller is something like this
public class HelloWorldControllerTest extends TestCase {
protected void setUp() throws Exception {
super.setUp();
}
protected void tearDown() throws Exception {
super.tearDown();
}
public void testHelloWorldController() throws IOException {
MockRenderRequest request = new MockRenderRequest();
HelloController c = new HelloController ();
ModelAndView result = c.helloWorld(request);
assertNotNull("ModelAndView should not be null", result);
assertEquals("hello", result.getViewName());
}
This is not working as the result is not a ModelAndView object but it is a String in the controller. The return type can be a ModelAndView object in the main controller but if using spring annotation based then from the examples I have found the return type is String. Can anyone suggest which is the best practice or if I am wrong in understanding.
Thanks in advance
The spring-test-mvc project facilitates testing Spring MVC controllers.
Checkout spring-test-portlet-mvc (https://github.com/markusf/spring-test-portlet-mvc) to integration test your Spring controllers.