I've written unit tests using NSubstitute library and faced with odd Records behavior.
Assuming I have the code:
public record SomeModel
{
//fields
}
public interface ISomeService
{
public string DoSmth(SomeModel model);
}
public class SomeClass
{
private ISomeService _service;
public SomeClass(ISomeService service)
{
_service = service;
}
public string MethodToTest(SomeModel model)
{
return _service.DoSmth(model);
}
}
And I want to cover it with the Unit test:
[Fact]
public void Test()
{
var model = Substitute.For<SomeModel>();
var service = Substitute.For<ISomeService>();
service.DoSmth(model).Returns("1234");
var sut = new SomeClass(service);
var value = sut.MethodToTest(model); //it returns Empty sting here
value.Should().Be("1234");
}
But it Fails, because MethodToTest returns Empty string.
If I change SomeModel from record to class it is working fine.
Could someone point me to what I missed here?
Update: I changed the model initialization in my test method:
[Fact]
public void Test()
{
var model = new SomeModel();
//other code
}
In this case, it is working. But I still don't understand why it isn't working in the initial example?
Update 2. It is even working if I use Substitute.ForPartsOf:
[Fact]
public void Test()
{
var model = Substitute.ForPartsOf<SomeModel>();
//other code
}
Related
I have a class that I am trying to test out through writing some unit test in C#. I am also using Moq library in my unit test for mocking.
Below are some of the methods in my class which I want to mock so that they can return some dummy data which I want to return always.
public class DataManager
{
public DataManager(ILoggingService loggingService, IConfiguration configuration)
{
// ...
}
// how to mock this to return dummy data?
private DataHolder GetData()
{
//... return DataHolder object
}
// how to mock this to return dummy data?
private IEnumerable<ProcessClient> GetClientValues(string value)
{
//... return IEnumerable<ProcessClient> object
}
}
This is how I am testing it out:
private Mock<ClientUtility> utility;
[SetUp]
public void Setup()
{
utility = new Mock<ClientUtility>();
}
[Test]
public void Test1()
{
// what should I do here so that "GetData" and "GetClientValues" return dummy data when I call below class constructor?
var testName = "config1";
var testContent = "{}";
utility.Setup(x => x.Add(new DataStatus { Pin = "test" }, "data.com", "test")).Returns(Task.FromResult(true));
var dataManager = new DataManager(loggingService.Object, configuration.Object);
Assert.AreEqual(testContent, dataManager.GetStuff(testName)[0]);
}
Question:
How can I mock "GetData" and "GetClientValues" using Moq or any other library to return dummy data from those two methods? Is this possible to do?
I think you can use CallBase = true.
So your mock will behave like true class.
var dataManager = new Mock<DataManager>(loggingService.Object, configuration.Object) { CallBase = true };
dataManager.Object.Method1();
dataManager.Object.Method2();
And you can mock some methods like you do with utility.
Search by "CallBase" on page:
https://github.com/Moq/moq4/wiki/Quickstart
UPDATE
I made methods public to call them.
And there is some issue, that i didn't see last time. You need to make "virtual" methods if you want change their behavior.
There is example of code. As you can see, GetClientValues() returns real data because we call default real implementation with CallBase = true and GetData() returns dummy data because we mocked its behavior.
public class DataManager
{
public DataManager(ILoggingService loggingService, IConfiguration configuration)
{
// ...
}
// how to mock this to return dummy data?
public virtual DataHolder GetData()
{
return new DataHolder
{
Data = "RealData"
};
}
// how to mock this to return dummy data?
public IEnumerable<ProcessClient> GetClientValues(string value)
{
return new List<ProcessClient>
{
new ProcessClient
{
Data = "RealData"
}
};
}
}
And tests.
public class Tests
{
[SetUp]
public void Setup()
{
}
[Test]
public void Test1()
{
var loggingService = new Mock<ILoggingService>();
var config = new Mock<IConfiguration>();
var dataManager = new Mock<DataManager>(loggingService.Object, config.Object){CallBase = true};
dataManager.Setup(x => x.GetData()).Returns(new DataHolder { Data = "FakeData" });
Assert.AreEqual("RealData", dataManager.Object.GetClientValues("test").First().Data);
Assert.AreEqual("FakeData", dataManager.Object.GetData().Data);
}
}
But anyway i think, that this approach isn't good for testing.
There is a problem with testing private methods. We have some ways (for example Invoke()), but in general, "if you want to unit test a private method, something may be wrong". I would like to recommend you to read something about test design and writing testable code.
About testing private methods How do you unit test private methods?.
I have Video Service class as follows:
public class VideoService
{
private IFileReader _fileReader;
private IVideoRepository _repository;
public string _videoPath;
public VideoService(IFileReader fileReader, IVideoRepository repository)
{
_fileReader = fileReader;
_repository = repository;
}
public string ReadVideoTitle()
{
var str = _fileReader.Read(_videoPath);
if (str == "")
{
return "";
}
else
{
return "b";
}
}
}
then there is IFileReader and FileReader as below:
public interface IFileReader
{
string Read(string path);
}
public class FileReader : IFileReader
{
public string Read(string path)
{
return File.ReadAllText(path);
}
}
Now i have my unit test:
[TestFixture]
public class VideoServiceTests
{
private VideoService _videoService;
private Mock<IFileReader> _fileReader;
private Mock<IVideoRepository> _repository;
private string _videoPath;
[SetUp]
public void SetUp()
{
_fileReader = new Mock<IFileReader>();
_repository = new Mock<IVideoRepository>();
_videoPath = #"test.txt";
_videoService = new VideoService(_fileReader.Object, _repository.Object);
}
[Test]
public void ReadVideoTitle_EmptyFile_ReturnError()
{
_fileReader.Setup(fr => fr.Read(_videoPath)).Returns("");
var result = _videoService.ReadVideoTitle();
Assert.That(result, Does.Contain("").IgnoreCase);
}
My problem is and what i am not understanding. When i do _fileReader.Setup ..
My understanding is it is a fake reader and not FileReader class right?, therefore when i say put whatever in Read parameter like: test.txt then i say i am expecting Returns "". In Assert i am comparing it to what i get from ReadVideoTitle. However what is the sense of Assert here? Since _fileReader is just interface and not real class it will not really look and try to read fake test.txt file and look for output. Therefore first question why i always get test Success whatever i put in _fileReader.Setup. How it checks whether is Success? Shouldn'e it be just Vlaidate() if Read was really called, since it's nt really testing values? Can anyone be so kind and explain me how current example test works and what is really testing because so far i am lost.
I've read through the examples on JustMock (we have the paid version FYI) but am having difficulty in regards to updating a record (not adding).
I have a ILogRepo of
public interface ILogRepo
{
DbSet<LogEntry> LogEntries { get; }
LogContext LogContext { get; }
}
I have a LogInteraction of
public class LogInteraction : ILogInteraction
{
private readonly ILogRepo _logRepo;
public LogInteraction(ILogRepo logRepo)
{
_logRepo = logRepo;
}
public void UpdateLog(IList<AckDetail> ackDetails)
{
foreach (var ackDetail in ackDetails)
{
var logRecord = _logRepo.LogEntries.Single(r => r.CheckNum == ackDetail.CheckNo);
logRecord.ProcessingStatus = ackDetail.Result.ToString();
if (!string.IsNullOrWhiteSpace(ackDetail.Message))
{
logRecord.Message = ackDetail.Message;
}
}
_logRepo.LogContext.SaveChanges();
}
}
I've mocked out a fake LogEntries (it's an IList). And last but not least a test of
[TestFixture]
public class LogTests
{
private ILogRepo _mockLogRepo;
private ILogInteraction _uut;
private IList<AckDetail> _fakeAckDetails;
[SetUp]
public void SetUp()
{
//Arrange
_mockLogRepo = Mock.Create<ILogRepo>();
_fakeAckDetails = FakeAckDetails();
_uut = new LogInteraction(_mockLogRepo);
}
[Test]
public void LogUpdated()
{
//Arrange
var expectedResults = FakeLogEntries_AfterAckProcessing();
var expectedJson = JsonConvert.SerializeObject(expectedResults);
_mockLogRepo.Arrange(m => m.LogEntries).IgnoreInstance().ReturnsCollection(FakeLogEntries_AfterSending());
//Act
_uut.UpdateLog(_fakeAckDetails);
var actualResults = _mockLogRepo.LogEntries.ToList();
var actualJson = JsonConvert.SerializeObject(actualResults);
//Assert
Assert.AreEqual(expectedResults.Count, actualResults.Count);
Assert.AreEqual(expectedJson, actualJson);
}
}
In my test, my _mockLogRepo is not being updated by my LogInteraction. Stepping through the code everything seems all well and good. If I inspect the context though and look for changes, that returns a false though. I think I've matched the example on Telerik's site pretty well, but I've only been able to find info on Adding (and by extrapolating, Removing). But since those two are actual methods and Updating isn't in Entity Framework I'm at a bit of a loss. My code will work in production, but I'd like it to work in Test too (kind of the whole point).
I am new to write Unit Tests. Therefore, I have been struggling with.
I need to insert product via an external WebService. Then the WebService will return a string that is necessary to update the product afterwards.
This is my ApiController:
public class ProductController : ApiController
{
private IProductRepository _ProductRepository;
private IWebService _WebService;
public ProductController(IProductRepository productRepository, IWebService webService)
{
_ProductRepository = productRepository;
_WebService = webService;
}
public HttpResponseMessage Add(string title)
{
using (TransactionScope scope = new TransactionScope())
{
Product product = new Product
{
Title = title
};
this._ProductRepository.Add(product);
// WebService will return a string
string result = this._WebService.Add(product.ID, DateTime.Now);
product.ServiceResult = result;
this._ProductRepository.Update(product);
scope.Complete();
}
return Request.CreateResponse(HttpStatusCode.Created);
}
}
I was wondering how should I write a unit test for this code?
I've tried to write it as follows: (with NUnit, Moq)
[TestFixture]
public class ProductControllerShould : AssertionHelper
{
private Mock<IWebService> _WebService;
private Mock<IProductRepository> _ProductRepository;
[SetUp]
public void Setup()
{
_WebService = new Mock<IWebService>();
_ProductRepository = new Mock<IProductRepository>();
}
[Test]
public void ReturnCreatedOnAdd()
{
_WebService.Setup(b => b.Add(1, DateTime.Now))
.Returns("0");
var controller = new ProductController(_ProductRepository.Object,
_WebService.Object);
var result = controller.Add("Lumia");
Expect(result, Is.EqualTo(HttpStatusCode.Created));
}
}
but when I debug the test, result in this line is null that is not correct.
string result = this._WebService.Add(product.ID, DateTime.Now);
Shouldn't this line handle the behaviour of _WebService.Add() and return "0"?
_WebService.Setup(b => b.Add(1, DateTime.Now))
.Returns("0");
I know I write the test incorrectly but I don't know what should I do.
Thanks.
The problem here, is that you are mocking call of static method `DateTime.Now' . But "Now" in the time point of mocking and as it is called are different. Therefore your call doesn't return anything.
I could suggest 3 following ways:
1) It doesn't really matter for you, if the call was with DateTime.Now or not, in that case you could ignore the second argument:
_WebService.Setup(b => b.Add(1, It.IsAny<DateTime>())).Returns("0");
2) You want to test, that the call was with DateTime.Now. In that case i create an interface for getting DateTime.Now:
public interface IDateTimeNowProvider
{
DateTime Now { get; }
}
public ProductController(IProductRepository productRepository,
IWebService webService,
IDateTimeNowProvider dateTimeNowProvider)
{
_ProductRepository = productRepository;
_WebService = webService;
_dateTimeNowProvider = dateTimeNowProvider;
}
In production code you use default implementation of it, that just returns DateTime.Now. But in your test class you do mock this interface with some predefined values and you test for using this value.
var now = DateTime.Parse("2017-01-22");
var _dateTimeNowProvider = new Mock<IDateTimeNowProvider>();
var controller = new ProductController(_ProductRepository.Object,
_WebService.Object, _dateTimeNowProvider.Object );
_dateTimeNowProvider.Setup(x => x.Now).Returns(now);
_WebService.Setup(b => b.Add(1,now)).Returns("0");
3) You could use special mocking framework that allows to mock static methods, as for example typemock isolator
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();
}
}