Using Shims to test private method - unit-testing

I am trying to use Shim to test one of my private method in this class called DataSyncCore.
Apologies if this is too trivial as i am new to shims and can't figure out why this is giving me an error saying "The property or indexer GetEnvironmentString cannot be used in this context as it is lacking an accessor. How can this be fixed?
//Method to be tested inside DataSyncCore Class
private Environments GetEnvironment(string env)
{
string environment = env.ToLower();
switch (environment)
{
case "dev":
return Environments.Dev;
case "qc":
return Environments.QC;
case "uat":
return Environments.UAT;
case "prod":
return Environments.PROD;
default:
return Environments.Dev;
}
}
This is my unit test:
[TestMethod]
public void DataSyncCore_GetsEnvironment_Succeeded()
{
using (ShimsContext.Create())
{
var core = new ShimDataSyncCore()
{
GetEnvironmentString = (dev) =>
{
return Environments.Dev;
}
};
Assert.AreEqual(Environments.Dev, core.GetEnvironmentString("dev"));
}
}

If you cannot make the class public, you can still use Activator.CreateInstance:
var anInstance = (YourPrivateClass)Activator.CreateInstance(typeof(YourPrivateClass), true);
Or, you could mark the method as internal and set InternalsVisibleTo attribute in your assemblyinfo if you want/need to test that method directly.

Related

Dependency Injection with Moq and AutoMoq (AutoFixture) w/ xUnit

I'm writing this because I've tried for a bit to figure this out myself with no luck. Every example I can find for whatever reason seems to suggest that this just works out of the box but whenever I try to do the same, I always get errors. Basically, I have a controller with two properties that are injected via. DI, let's say
public class SomeController
{
private ISomeInterface _i;
private MyConfig _c;
public SomeController(ISomeInterface i, MyConfigContext cxt) // Where cxt is Type of DbContext
{
_i = i;
_c = cxt.Configs.FirstOrDefault();
}
public OkResult PostModel(SomeModel c)
{
// Do things
return Ok();
}
}
And in my tests using xUnit, Moq & AutoFixture I'm trying to avoid having to manually instantiate dependencies B and C:
public class SomeControllerTests
{
private MyDbContext _cxt;
private Fixture _fixture;
public SomeControllerTests()
{
_cxt = GetCxt() // GetCxt() just returns a context instance, nothing special
_fixture = new Fixture();
_fixture.Customize(new AutoMoqCustomization { ConfigureMembers = true });
_fixture.Customizations.Add(
new TypeRelay(
typeof(ISomeInterface),
typeof(SomeConcreteClass)
)
);
}
[Fact, AutoData]
public void PostStatus_ReturnsOk_GivenValidRequest()
{
SomeController c = _fixture.Create<SomeController>();
SomeModel m = _fixture.Create<SomeModel>();
var result = c.PostModel(m);
Asset.IsType<OkResult>(result);
}
}
With the above I am getting a NotImplementedException when I run the tests and it won't tell me what exactly is not being implemented so I have no way of knowing what the issue is. I must be missing something in the docs. I want to use AutoFixture to make my tests more durable but so far it has been a pain trying to use it. I really don't want to have to mock/stub my entire app manually just to run a test. I would ideally like to use the syntax shown in the AutoFixture docs where you put your test-relevant instances in the params of the test and they are created for you but I haven't had any luck with it, like...
[Theory, AutoData]
SomeTestMethod(SomeController c, SomeModel m)
{
var result = c.PostModel(m);
Assert.IsType<OkResult>(result);
}
Thanks for Reading (:
Try to add next attribute and use it instead of AutoData.
using AutoFixture.AutoMoq;
using AutoFixture.Xunit2;
namespace Cats
{
public class AutoMoqDataAttribute : AutoDataAttribute
{
public AutoMoqDataAttribute()
: base(() => new Fixture().Customize(new AutoMoqCustomization()))
{
}
}
}
[Theory, AutoMoqData]
SomeTestMethod(SomeController c, SomeModel m)
{
var result = c.PostModel(m);
Assert.IsType<OkResult>(result);
}

MVC Core 2.0 Unit Testing and Automapper

I am attempting to Unit Test a method that uses Automapper ProjectTo and I'm not sure how to register the mappings in MVC Core. I am using the built in unit testing.
The following is my unit test.
[TestClass]
public class BusinessGenderServiceTest
{
[ClassInitialize]
public static void Init(TestContext context)
{
}
[TestMethod]
public void GetTest()
{
var options = new DbContextOptionsBuilder<GotNextDbContext>()
.UseInMemoryDatabase(databaseName: "GetTest")
.Options;
using (var context = new GotNextDbContext(options))
{
context.GenderLanguage.Add(new GenderLanguage { Id = 1, Name = "Male", Language = 1 });
context.GenderLanguage.Add(new GenderLanguage { Id = 2, Name = "Female", Language = 1 });
context.GenderLanguage.Add(new GenderLanguage { Id = 3, Name = "Hombre", Language = 2 });
context.GenderLanguage.Add(new GenderLanguage { Id = 4, Name = "Hombre", Language = 2 });
context.SaveChanges();
}
using (var context = new GotNextDbContext(options))
{
var service = new GenderService(context);
var result = service.Get(1);
Assert.AreEqual(2, result.Count());
}
}
}
I am getting the following error when I run the test:
Message: Test method GotNext.Test.BusinessGenderServiceTest.GetTest threw exception:
System.InvalidOperationException: Mapper not initialized. Call Initialize with appropriate configuration. If you are trying to use mapper instances through a container or otherwise, make sure you do not have any calls to the static Mapper.Map methods, and if you're using ProjectTo or UseAsDataSource extension methods, make sure you pass in the appropriate IConfigurationProvider instance.
I was able to solve this problem by configuring and initializing automapper in the Init method of each test class.
For example
[ClassInitialize]
public static void Init(TestContext testContext)
{
var mappings = new MapperConfigurationExpression();
mappings.AddProfile<LocationProfile>();
mappings.AddProfile<CompanyProfile>();
Mapper.Initialize(mappings);
}
You can configure AutoMapper in class like this:
public static class AutoMapperConfig
{
public static IMapper Initialize()
{
return new MapperConfiguration((cfg =>
{
cfg.CreateMap<User, UserDto>();
})).CreateMapper();
}
}
And next use it in startup.cs ConfigureService method
services.AddSingleton(AutoMapperConfig.Initialize());
Create a class or classes that configure AutoMapper and instantiate (and call methods, if applicable) in the Startup class.
I got this same error ("System.InvalidOperationException: Mapper not initialized. Call Initialize with appropriate configuration. ...") when I inadvertently / mindlessly switched between AutoMapper's Instance API (which I did have configured) and AutoMapper's Static API (which I did NOT have configured).
Looking closely at the line of code flagged in the error message, I realized I used upper-case 'M' Mapper.Map() instead of my instance member lower-case 'm' mapper.Map().

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

How do I run my NUnit test cases using Selenium to run against different environments?

I have written NUnit test cases using Selenium to test a web application. And I would like to run the same test cases against different environments (e.g. QA, Staging, & Production) What's the easiest way to achieve that?
NUnit supports parametrised test fixtures as well as parametrised tests. So the first thing is that are you going to want to run specific tests against different environments, or is it the entire test fixture will be rerun for both environments?
I ask because the answer to this determines where you will pass the parameter (the environment). If you are just wanting to rerun the whole test fixture, you should pass the environment in at a test fixture level, that is to create parametrised test fixtures. If you want to run only particular tests against those environment, you'll have to pass it in to each individual test case. An example is below of how I've gone about the same sort of thing:
First create a way to define what 'environment' the tests can 'attach' to. I'd suggest perhaps shoving this into the app.config and have a 'Settings' class and an enum to go with it:
public enum Environment
{
QA,
Production,
Hotfix,
Development
}
public class Settings
{
public static string QAUrl { get { return "some url"; } }
public static string ProductionUrl { get { return "some url"; } }
public static string HotfixUrl { get { return "some url"; } }
public static string DevUrl { get { return "some url"; } }
}
The above "some url" would be read from your configuration file or hardcoded, however you please.
We've now got a concept of an environment, and it's URL, but they are not linked together or related in any way. You would ideally want to give it the 'QA' value of your enum and then it will sort out the URL for you.
Next create a base test fixture that all your test fixtures can inherit from, which keeps hold of the current environment. We also create a Dictionary that now relates the environment value to it's URL:
public class BaseTestFixture
{
private Dictionary<Environment, string> PossibleEnvironments
{
get
{
return new Dictionary<Environment, string>()
{
{ Environment.QA, Settings.QAUrl },
{ Environment.Production, Settings.ProductionUrl },
{ Environment.Hotfix, Settings.HotfixUrl },
{ Environment.Development, Settings.DevelopmentUrl },
}
}
}
private Environment CurrentEnvironment { get; set; }
public BaseTestFixture(Environment environment)
{
CurrentEnvironment = environment;
}
}
You could probably use Reflection to have it work out what URL's map to what enum value's.
So cool, we've got an environment we can run against. A sample test to go to login as an administrator to your site:
public class LoginToSite
{
[Test]
public void CanAdministratorSeeAdministratorMenu()
{
// go to the site
driver.Navigate().GoToUrl("production site");
// login as administrator
}
}
How do we get this to go to the specific URL? Let's modify our base class a little...
public class BaseTestFixture
{
private Dictionary<Environment, string> PossibleEnvironments
{
get
{
return new Dictionary<Environment, string>()
{
{ Environment.QA, Settings.QAUrl },
{ Environment.Production, Settings.ProductionUrl },
{ Environment.Hotfix, Settings.HotfixUrl },
{ Environment.Development, Settings.DevelopmentUrl },
}
}
}
private Environment CurrentEnvironment { get; set; }
protected string CurrentEnvironmentURL
{
get
{
string url;
if (PossibleEnviroments.TryGetValue(CurrentEnviroment, out url))
{
return url;
}
throw new InvalidOperationException(string.Format("The current environment ({0}) is not valid or does not have a mapped URL!", CurrentEnviroment));
}
}
public BaseTestFixture(Environment environment)
{
CurrentEnvironment = environment;
}
public BaseTestFixture()
{
}
}
Our base class now can tell us, depending on what environment we are in, what page to go to...
So we now have this test, inheriting from our base:
public class LoginToSite : BaseTestFixture
{
[Test]
public void CanAdministratorSeeAdministratorMenu()
{
// go to the site
driver.Navigate().GoToUrl(CurrentEnvironmentURL);
// login as administrator
}
}
However, that's great, but the above won't compile...why? We are not actually giving it an environment yet so we must pass one in...
[TestFixture(Environment.QA)]
public class LoginToSite : BaseTestFixture
{
[Test]
public void CanAdministratorSeeAdministratorMenu()
{
// go to the site
driver.Navigate().GoToUrl(CurrentEnvironmentURL);
// login as administrator
}
}
That's great, it now has the environment passed in, the checking of the URL etc are all done in the background for you now...however this still won't compile. Since we are using inheritance, we have to have a constructor to pass it down for us:
public LoginToSite(Environment currentEnvironment)
{
CurrentEnvironment = currentEnvironment;
}
Et voilĂ .
As for specific test cases, this is a little easier, taking our test case from earlier:
public class LoginToSite
{
[TestCase(Environment.QA)]
public void CanAdministratorSeeAdministratorMenu(Environment environment)
{
// go to the site
driver.Navigate().GoToUrl("production site");
// login as administrator
}
}
Which would pass in the environment into that specific test case. You would then need a new Settings class of some sort, to do the environment checking for you (in a similar way as I did before):
public class EnvironmentHelper
{
private static Dictionary<Environment, string> PossibleEnvironments
{
get
{
return new Dictionary<Environment, string>()
{
{ Environment.QA, Settings.QAUrl },
{ Environment.Production, Settings.ProductionUrl },
{ Environment.Hotfix, Settings.HotfixUrl },
{ Environment.Development, Settings.DevelopmentUrl },
}
}
}
public static string GetURL(Environment environment)
{
string url;
if (PossibleEnviroments.TryGetValue(environment, out url))
{
return url;
}
throw new InvalidOperationException(string.Format("The current environment ({0}) is not valid or does not have a mapped URL!", environment));
}
}
Best way would be to use variables instead of hard coded links for all functions. So that it can be changed when needed to change the environment. An easier approach would be to read links from a notepad/excel file .

How do you test an extension method on an Interface which calls another method in that Interface with a mock created by Rhino Mocks?

I'm testing an extension method on an interface 'ISomeInterface'. The extension method actually calls to another method in the interface.
How do I set up a mock and the appropriate expectations (i want to set the expectation that 'SomeMethod', which is an defined method in the interface with a different signature then this extension method, will be called with 'someDifferentParam')
// Extension Method
public static ISomeInterface SomeMethod(this ISomeInterface someInterface, string someParam)
{
// do work, then call the defined method in the interface
someInterface.SomeMethod(int someDifferentParam)
return someInterface;
}
// tried to do the following but it errors
[Test]
public void SomeMethod_WithSomeInterface_CallsOtherSomeMethod()
{
const string someParam = "something";
const int someOtherParam = 1;
var mock = MockRepository.GenerateMock<ISomeInterface>();
mock.SomeMethod(someParam);
mock.AssertWasCalled(x => x.SomeMethod(someOtherParam));
}
EDIT
I finally got it working, but I'm open to suggestions/criticism. I'm just learning the ins/outs of Rhino Mocks myself =)
here is the real thing that I was testing. Since you can't compare two NHibernate.Criterion.Order objects by doing an Is.Equal or Is.SameAs I had to capture the arguments passed to the method call and then Assert on the ToString of the Order object because there are no public properties exposed on it.
// Extension Method
public static class NHibernateExtensions
{
public static ICriteria AddOrder(this ICriteria criteria, params OrderBy[] orderBys)
{
foreach (var b in orderBys)
{
var arr = b.Property.Split(',');
for (var i = 0; i < arr.Length; i++)
{
criteria.AddOrder(b.Direction == OrderDirection.Ascending
? Order.Asc(arr[i])
: Order.Desc(arr[i]));
}
}
return criteria;
}
}
// here is the test that works
[TestFixture]
public class NHibernateExtensionsTester : TestBase
{
[Test]
public void AddOrder_1OrderBy_CallsAddOrderOnICriteriaWithCorrectOrder()
{
const string testProperty = "SomeProperty";
var expected = (Order.Asc(testProperty)).ToString();
var orderBys = new[]
{
new OrderBy
{
Direction = OrderDirection.Ascending,
Property = testProperty
}
};
var mockCriteria = M<ICriteria>();
mockCriteria.AddOrder(orderBys);
var orderArgument = (Order)((mockCriteria.GetArgumentsForCallsMadeOn(x => x.AddOrder(null)))[0][0]);
Assert.That(orderArgument.ToString(), Is.EqualTo(expected));
}
}
Jon, since in effect you're just testing your extension method I see nothing wrong and this. I tried your code out and worked fine for me. Here is the exact code that I ran (using xunit.net and TD.Net). The test passed.
What error are you getting?