I have a singleton class and I want to run some unit tests in isolation. The problem is that all the tests run on the same instance and affect the expected results. Is there a workaround? I am using .net 6 and NUnit 3. Here's my code,
public interface ISingletonModel<T>
{
void AddValue(string key, T value, LinkedListNode node);
}
public sealed class SingletonModel<T> : ISingletonModel<T>
{
public Dictionary<string, (LinkedListNode<string> node, T value)> ModelDictionary { get; set; }
private static readonly Lazy<SingletonModel<T>> singletonModel=
new Lazy<SingletonModel<T>>(() => new SingletonModel<T>());
public static SingletonModel<T> Instance
{
get
{
return SingletonModel.Value;
}
}
private SingletonModel()
{
ModelDictionary = new Dictionary<string, (node, T value)>();
}
}
public void AddValue(string key, T value, LinkedListNode node)
{
if (ModelDictionary.ContainsKey(key))
{
var linkedListNode = ModelDictionary[key];
ModelDictionary[key] = (node, value);
}
else
{
ModelDictionary.Add(key, (node.AddFirst(key), value));
}
}
}
And some unit tests
private TestClass[] testData;
private IFixture fixture;
private SingletonModel<TestClass> model;
[SetUp]
public void Setup()
{
this.testData = GenerateTestData();
this.model= SingletonModel<TestClass>.Instance;
}
[Test]
public void CheckModelCapacity_ShouldReturnTheCorrectItems()
{
/ Act
foreach (var entity in testData)
{
this.model.AddValue(entity.Id, entity, entity.node);
}
IEnumerable<string> expected = new[] { "8", "3", "5", "2", "79" };
var actual = this.model.ModelDictionary.Keys.ToList();
// Assert
Assert.That(expected.OrderBy(x => x).SequenceEqual(actual.OrderBy(x => x)));
}
[Test]
public void CheckTotalItems_ShouldReplaceItemsWithTheSameKey()
{
// Assign
var entity1 = fixture.CreateMany(20);
// Act
foreach (var item in entity1)
{
this.model.AddValue(item.Id, item, item.node);
}
//Assert
Assert.AreEqual(2, this.model.ModelDictionary.Count);
}
Because of the singleton the tests are holding the values from the previous tests.
A public or internal constructor would allow for creating isolated instances in tests, but if the intention here is to not modify the current class then reflection can be used to access the private constructor to create isolated instances for tests.
Here is a simplified model based on the original since it was incomplete and wouldn't compile.
public interface ISingletonModel<T> {
void AddValue(string key, T value);
int Count { get; }
}
public sealed class SingletonModel<T> : ISingletonModel<T> {
Dictionary<string, T> dictionary;
private static readonly Lazy<SingletonModel<T>> singletonModel = new Lazy<SingletonModel<T>>(() => new SingletonModel<T>());
public static SingletonModel<T> Instance => singletonModel.Value;
private SingletonModel() {
dictionary = new Dictionary<string, T>();
}
public void AddValue(string key, T value) => dictionary[key] = value;
public int Count => dictionary.Count;
}
Using one of the overloads of Activator.CreateInstance:
Activator.CreateInstance(Type type, bool nonPublic)
which uses reflection to access the private constructor, shows that instances can be created to be tested in isolation
public class Program {
public static void Main() {
//Arrange
int expected = 1;
ISingletonModel<int> model1 = (ISingletonModel<int>)Activator.CreateInstance(typeof(SingletonModel<int>), true);
//Act
model1.AddValue("one", 1);
//Assert
int actual = model1.Count;
Console.WriteLine($"{actual}, As expected: {actual == expected}");
//Arrange
expected = 3;
ISingletonModel<int> model2 = (ISingletonModel<int>)Activator.CreateInstance(typeof(SingletonModel<int>), true);
//Act
model2.AddValue("one", 1);
model2.AddValue("two", 2);
model2.AddValue("three", 3);
//Assert
actual = model2.Count;
Console.WriteLine($"{actual}, As expected: {actual == expected}");
//Arrange
expected = 2;
ISingletonModel<int> model3 = (ISingletonModel<int>)Activator.CreateInstance(typeof(SingletonModel<int>), true);
//Act
model3.AddValue("one", 1);
model3.AddValue("two", 2);
//Assert
actual = model3.Count;
Console.WriteLine($"{actual}, As expected: {actual == expected}");
}
}
which return the following output
1, As expected: True
3, As expected: True
2, As expected: True
Add ResetForTesting() method your singleton class?
Related
I can't get Moq to mock an object that gets created in a static method.
Here is my moq and code
code:
public interface IConfigHelper
{
string GetConfiguration(string sectionName, string elementName);
}
public class ConfigHelper : IConfigHelper
{
public ConfigHelper() { }
public virtual string GetConfiguration(string sectionName, string elementName)
{
string retValue = String.Empty;
//Does things to get configuration and return a value
return retValue;
}
}
public class myRealClass
{
public myRealClass(){}
public string myworkingMethod()
{
var retValue = String.Empty;
retValue = utilSvc.GetConfigurationValue();
return retValue;
}
}
public static class utilSvc
{
public static string GetConfigurationValue()
{
ConfigHelper configUtil = new ConfigHelper(); //NOT BEING MOCKED
return configUtil.GetConfiguration("sectionName/sectionElement", "ClinicalSystem");
}
}
the Test using Moq
[TestFixture(TestName = "Tests")]
public class Tests
{
private Mock<IConfigHelper> configHelperMOCK;
[SetUp]
public void Setup()
{
configHelperMOCK = new Mock<IConfigHelper>();
}
[Test]
public void serviceIsBPManagementForValidSource()
{
//Arrange
string sectionName = "sectionName/sectionElement";
string clinicalElementName = "ClinicalSystem";
string clinicalElementValue = "Zedmed";
configHelperMOCK.Setup(s => s.GetConfiguration(sectionName, clinicalElementName)).Returns(clinicalElementValue);
//act
// the call to myRealClass
//assert
// test assertions
}
}
The issue that I am having is with this line:
ConfigHelper configUtil = new ConfigHelper(); //NOT BEING MOCKED
I cannot get the moq to Mock the object.
I do not want the code to read the config file. I wish to moq away this instance of ConfigHelper
You can't wrap the static class/method but you can redirect it
public static class UtilSvc
{
static UtilSvc()
{
CreatorFunc = () => new ConfigHelper();
}
public static Func<IConfigHelper> CreatorFunc { get; set; }
public static string GetConfigurationValue()
{
var configUtil = CreatorFunc();
return configUtil.GetConfiguration("sectionName/sectionElement",
"ClinicalSystem");
}
}
and then in the test
//...
private Mock<IConfigHelper> configHelperMOCK;
[SetUp]
public void Setup()
{
configHelperMOCK = new Mock<IConfigHelper>();
UtilService.CreatorFunc = () => configHelperMOCK.Object;
}
//...
You cannot mock static class. I would rather propose to inject that IConfigHelper into the myRealClass. That is the usual way how to decouple dependencies and use DI.
public class myRealClass
{
private IConfigHelper _configHelper;
public myRealClass(IConfigHelper configHelper)
{
_configHelper = configHelper;
}
public string myworkingMethod()
{
var retValue = String.Empty;
retValue = _configHelper.GetConfigurationValue();
return retValue;
}
}
Avoid coupling your code to static classes, which in most cases cause you code be to difficult to maintain and test.
Follow the Explicit Dependencies Principle
Methods and classes should explicitly require (typically through
method parameters or constructor parameters) any collaborating objects
they need in order to function correctly.
Give the article a read. It is short and very informative.
If you want to keep the static class then you wrap the static class behind an abstraction.
public interface IUtilSvc {
string GetConfigurationValue();
}
public class utilSvcWrapper : IUtilSvc {
public string GetConfigurationValue() {
return utilSvc.GetConfigurationValue(); //Calling static service
}
}
Or another option is that utlSvc does not have to be static if can be injected into dependent classes
public class utilSvc : IUtilScv {
private readonly IConfigHelper configUtil;
public utilSvc(IConfigHelper configHelper) {
configUtil = configHelper;
}
public string GetConfigurationValue() {
return configUtil.GetConfiguration("sectionName/sectionElement", "ClinicalSystem");
}
}
Inject the IUtilScv into the dependent class so that it is no longer dependent on static class.
public class myRealClass {
private readonly IUtilScv utilSvc;
//Explicit dependency inject via constructor
public myRealClass(IUtilScv utilSvc) {
this.utilSvc = utilSvc;
}
public string myworkingMethod() {
var retValue = utilSvc.GetConfiguration();
return retValue;
}
}
In that case you don't even need IConfigHelper when testing as it has also been abstracted away. And you only need to mock the dependencies needed for the test.
[TestFixture(TestName = "Tests")]
public class Tests {
private Mock<IUtilScv> utilScvMOCK;
[SetUp]
public void Setup() {
utilScvMOCK = new Mock<IUtilScv>();
}
[Test]
public void serviceIsBPManagementForValidSource() {
//Arrange
var expectedClinicalElementValue = "Zedmed";
utilScvMOCK
.Setup(s => s.GetConfiguration())
.Returns(expectedClinicalElementValue)
.Verifiable();
var sut = new myRealClass(utilScvMOCK.Object);
//Act
var actualClinicalElementValue = sut.myworkingMethod();
//Assert
configHelperMOCK.Verify();
Assert.AreEqual(expectedClinicalElementValue, actualClinicalElementValue);
}
}
I am testing my class
public class myclass
{
private IAwesome awesomeObject;
public myclass(IAwesome awesomeObject)
{
this.awesomeObject = awesomeObject;
}
public void MethodUnderTest()
{
this.awesomeObject.RunSomething(); //I want to verify that RunSomething was called
}
}
The way I am doing this is:
//Arrange
var mockAwesome = new Mock<IAwesome>();
mockAwesome.Setup(x=>x.RunSomething()).Returns ... Verify()...;
//Act
var sut = new myclass(mockAwesome.object);
sut.MethodUnderTest();
//Assert
mockAwesome.Verify();
The exception I am getting is:
System.NotSupportedException : Expression references a method that
does not belong to the mocked object: x => x.RunSomething
Is it not possible to test that a specific method was executed on a mocked object that I passed into a class, that is now part of a private member of that class?
Modify set up line to mockAwesome.Setup(x=>x.RunSomething()).Verifiable() and it should work for the example you provided.
[TestClass]
public class MoqVerificationTest {
[TestMethod]
public void Moq_Should_Verify_Setup() {
//Arrange
var mockAwesome = new Mock<IAwesome>();
mockAwesome.Setup(x => x.RunSomething()).Verifiable();
//Act
var sut = new myclass(mockAwesome.Object);
sut.MethodUnderTest();
//Assert
mockAwesome.Verify();
}
public interface IAwesome {
void RunSomething();
}
public class myclass {
private IAwesome awesomeObject;
public myclass(IAwesome awesomeObject) {
this.awesomeObject = awesomeObject;
}
public void MethodUnderTest() {
this.awesomeObject.RunSomething(); //I want to verify that RunSomething was called
}
}
}
To confirm, comment out this.awesomeObject.RunSomething() in your sample class and run the test again. It will fail because you setup the RunSomething as Verifiable() and it was not used.
When testing, works perfectly fine for me...
Try this approach see if anything different results...
void Main()
{
IAwesome awesome = Mock.Of<IAwesome>();
Mock<IAwesome> mock = Mock.Get(awesome);
mock.Setup(m => m.RunSomething());
MyClass myClass = new MyClass(awesome);
myClass.MethodUnderTest();
mock.Verify(m => m.RunSomething(), Times.Once);
}
public interface IAwesome
{
void RunSomething();
}
public class MyClass
{
private IAwesome awesomeObject;
public myclass(IAwesome awesomeObject)
{
this.awesomeObject = awesomeObject;
}
public void MethodUnderTest()
{
this.awesomeObject.RunSomething();
}
}
I have a class that has an ICollection property that is assigned by the constructor when the class is instantiated, but I want to bind this property to the original collection so that when it's updated/changed, the original list is as well. What is the best method of doing this?
Here's an example:
public class Organizations
{
private ICollection<Organization> _orgs;
public Organizations(ICollection<Organization> orgs)
{
_orgs = orgs;
}
public void TestAdd()
{
_orgs.Add(new Organization {Name = "Testing 123"});
}
}
// in another class
public ActionResult TestApi()
{
var tmp = new SyncTool.Core.Extensions.Zendesk.Organizations(ZendeskCache.Organizations.Data);
var zd = ZendeskCache.Organizations.Data.FirstOrDefault(n => n.Name.Contains("Testing 123"));
//ZendeskCache.Org.... is a List<Organization>
return Json(new {data = "tmp" }, AG);
}
The List<Organization> you are passing to the constructor is a reference object. This code works the way you want it to (aside from syntax errors), have you tried it out?
To reproduce more simply:
public class Program
{
public static void Main(string[] args)
{
var orgs = new List<string>();
var orgClass = new Organizations(orgs);
orgClass.TestAdd();
Console.WriteLine(orgs.First());
Console.Read();
}
}
public class Organizations
{
private ICollection<string> _orgs;
public Organizations(ICollection<string> orgs)
{
_orgs = orgs;
}
public void TestAdd()
{
_orgs.Add("Testing 123");
}
}
//Output: "Testing 123"
I want to ask what is a good unit test for the method below GetMeetingsByInterimIdentifier where interim identifier is a string -- such as 78th2015.
We are setup to use the interface IMeetingsService. We are using MOQ and Microsoft.VisualStudio.TestTools.UnitTesting.
public class MeetingsService : IMeetingsService
{
private readonly IInterimCommitteeDbContext _db;
public MeetingsService(IInterimCommitteeDbContext db)
{
this._db = db;
}
public IQueryable<Meeting> GetMeetingsByInterimIdentifier(string interimIdentifier)
{
return
from m in this._db.Meetings
join c in this._db.Committees on m.CommitteeId equals c.CommitteeId
where c.InterimIdentifier == interimIdentifier
select m;
}
public Meeting GetMeeting(int meetingKey)
{
return this._db.Meetings.FirstOrDefault(x => x.MeetingId == meetingKey);
}
}
Edit:
But I am not sure how to set it up. This result is not null, but what does it do for me?
[TestMethod]
public void GetMeetingsByInterimIdentifier_WithInterimIdentifier_ReturnsMeetingList()
{
//Arrange
var interim = Properties.Settings.Default.DefaultInterimIdentifier;
var result = _meetingServiceMock.Setup(x => x.GetMeetingsByInterimIdentifier(interim));
//Act
//Assert
Assert.IsNotNull(result);
}
Create a Mock<IInterimCommitteeDbContext> and pass it into the constructor. On this object setup the Meetings and Committees properties to return various collections.
You should have different tests setup that return different collections. For example, how should this behave if both the Meetings and Committees are empty, i.e. there is no data in the database? How should it behave if there isn't an object with the provided InterimIdentifier? What about if there is one that matches etc.
I figured out how to do this using test doubles. I am using Entity Framework 6 with the code first model. I created a DbContext that inherited from my I-DbContext interface. Then I was able to create in-memory data to use in my service layer unit tests. Below is an example of:
the test data context,
the test dbset,
an example unit test.
This solution was available from an msdn article here:
https://msdn.microsoft.com/en-us/data/dn314429.aspx
...
public class CommitteeContextTest : ICommitteeDbContext
{
public CommitteeContextTest()
{
this.Committees = new TestDbSet();
this.CommitteeMembers = new TestDbSet();
}
public Database Database { get; }
public DbSet Committees { get; set; }
public DbSet CommitteeMembers { get; set; }
}
}
public class TestDbSet : DbSet, IQueryable, IEnumerable, IDbAsyncEnumerable
where TEntity : class
{
ObservableCollection _data;
IQueryable _query;
public TestDbSet()
{
_data = new ObservableCollection();
_query = _data.AsQueryable();
}
public override TEntity Add(TEntity item)
{
_data.Add(item);
return item;
}
public override TEntity Remove(TEntity item)
{
_data.Remove(item);
return item;
}
public override TEntity Attach(TEntity item)
{
_data.Add(item);
return item;
}
public override TEntity Create()
{
return Activator.CreateInstance();
}
}
[TestClass]
public class CommitteeServiceTest
{
private InterimCommitteeContextTest _interimCommitteeContext;
private ICommitteeService _service;
private string _interim;
[TestInitialize]
public void SetUp()
{
_interimCommitteeContext = new InterimCommitteeContextTest();
_service = new CommitteeService(_interimCommitteeContext);
_interim = Settings.Default.DefaultInterimIdentifier;
}
[TestCleanup]
public void Teardown()
{
_interimCommitteeContext = null;
_service = null;
}
[TestMethod]
public void GetCommittee_ProvideInterimCommitteeId_ReturnOneCommittee()
{
//Arrange
AddCommittees();
//Act and Assert
var result = _service.GetCommittee(_interim, 1);
Assert.AreEqual(1, result.CommitteeId); //Passes. IsActive set to true;
result = _service.GetCommittee(_interim, 0);
Assert.IsNull(result); //Fails. No committeeId = 0;
result = _service.GetCommittee(_interim, 2);
Assert.IsNull(result); //Fails. CommitteeId = 2 is not active.
}
[TestMethod]
public void AddCommittees()
{
_interimCommitteeContext.Committees.Add(new Committee() { CommitteeId = 1, InterimIdentifier = _interim, IsActive = true, CommitteeTypeId = 1 });
_interimCommitteeContext.Committees.Add(new Committee() { CommitteeId = 2, InterimIdentifier = _interim, IsActive = false, CommitteeTypeId = 1 });
_interimCommitteeContext.Committees.Add(new Committee() { CommitteeId = 3, InterimIdentifier = _interim, IsActive = true, CommitteeTypeId = 1 });
}
}
Use Mocking, that's what it is for. Use JMock or Mockito or any other library you prefer.
How can i Mock list of object in for loop
Here is the code:`
public class SearchResult<T>
{
private readonly ISearcher<T> _searcher;
private readonly IList<ISearchConfigurator> _configurators;
public SearchResult(ISearcher<T> searcher, IList<ISearchConfigurator> configurators)
{
_searcher = searcher;
_configurators = configurators;
}
public DomainSearchResult<T> FindInAllDomains()
{
DomainSearchResult domainSearchResults = new DomainSearchResult<T>();
foreach (var configurator in _configurators)
{
IList<T> results = _searcher.SearchAll(configurator);
domainSearchResults.Results.Add(_configurator.DomainName, results);
}
return domainSearchResults;
}
}`
the property result is declared in the DomainSearchResult class :
IDictionary<string,IList<T>> Results { get; set; }
then i tried the following:
[Test]
public void FindInAllDomains_ReturnsAllRecord()
{
//Arrange
var configuratorMock = MockRepository.GenerateStub<IList<ISearchConfigurator>>();
var searchMock = MockRepository.GenerateMock<ISearcher<NativeDs>>();
var searchRestul = new SearchResult<NativeDs>(searchMock, configuratorMock);
//Act
searchRestul.FindInAllDomains(); // calling test fail here
//Assert
searchMock.AssertWasCalled(x => x.SearchAll(null), opt => opt.IgnoreArguments());
}
Error is:
System.NullReferenceException : Object reference not set to an instance of an object.
Try this...
var list = new List<ISearchConfigurator>
(from x in Enumerable.Range(1, 100)
select MockRepository.GenerateMock<ISearchConfigurator>()
);