I have the following class that has two static methods Retrieve and RetrieveWithQuery.
Below the classes listed here, I have included a snippet of the test.
All but the last assert of the test fails with the following message:
Failed TestMethod2 MoqTest Assert.AreEqual failed. Expected:. Actual:<(null)>.
I understand that the problem may be that the query that I setup in the mock
is a different instance from the query used in the RetrieveWithQuery method.
And that is why is would be returning null.
In a perfect world I would simply re-factor the service class, unfortunately I am
working with legacy code that is already production. The goal is to first complete
tests, then re-factor code and run regression testing before updating production
environment.
Is there a workaround or different way to test this?
public class MyService
{
public virtual string RetrieveMethod(string account)
{
if (account == "The abc company")
{
return "Peter Smith";
}
return "John Doe";
}
public virtual string RetrieveMethod(MyQuery query)
{
return RetrieveMethod(query.QueryString);
}
public static string Retrieve(MyService service, string value)
{
return service.RetrieveMethod(value);
}
public static string RetrieveWithQuery(MyService service, string value)
{
var query = new MyQuery
{
QueryString = value
};
return service.RetrieveMethod(query);
}
}
public class MyQuery
{
public string QueryString;
}
[TestMethod]
public void TestMethod2()
{
var mockService = new Mock<MyService>();
const string company = "The abc company";
const string expectedContact = "Peter Smith";
var queryAccount = new MyQuery
{
QueryString = company
};
// Setup base retrieve
mockService.Setup(myServ => myServ.RetrieveMethod(company)).Returns(expectedContact);
// Setup base retrieve with query
mockService.Setup(myServ => myServ.RetrieveMethod(queryAccount)).Returns(expectedContact);
// test base retrieve with query - PASS
Assert.AreEqual(expectedContact, mockService.Object.RetrieveMethod(queryAccount));
// test static method retrieve - PASS
Assert.AreEqual(expectedContact, MyService.Retrieve(mockService.Object, company));
// test static method retrieve with query - FAIL
Assert.AreEqual(expectedContact, MyService.RetrieveWithQuery(mockService.Object, company));
}
Try this for your setup:
// Setup base retrieve with query
mockService.Setup(myServ => myServ.RetrieveMethod(It.Is<Query>(q=>q.QueryString == queryAccount.QueryString)).Returns(expectedContact);
Or you could overload on Equals for Query so that the Query that gets created is equal to expectedQuery.
The Moq QuickStart page has good examples of this and more which should help a lot.
Related
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.
I'm new to Unit Testing and I'm using Rhino Mock in ASP.NET MVC
I have created a main test class with this code :
[TestFixture]
public class PersistenceTest
{
[Test]
protected T SaveAndLoadEntity<T>(T entity) where T : BaseEntity
{
var mockDataSource = MockRepository.GenerateMock<IRepository<T>>();
mockDataSource.Add(entity);
var fromDb = mockDataSource.FindBy(entity.Id);
return fromDb;
}
}
and create a customer test class like this :
[TestFixture]
public class CustomerTests : PersistenceTest
{
[Test]
public void Can_Save_And_Load_Customer()
{
var customer = new Customer()
{
Id = 12,
Name = "Reza",
Family = "Pazooki",
Company = "Rozaneh",
Email = "ipazooki#gmail.com",
Mobile = "09352463668",
Fax = "021-44869059",
Tel = "021-44869059",
WebSite = "www.rozanehmedia.com"
};
var fromDb = SaveAndLoadEntity(customer);
fromDb.ShouldNotBeNull();
}
}
but when run the code, it says that return value from Database is NULL!!!
I don't know what is wrong with my code but I save and retrieve data from mock repository and it seems every thing is ok.
tnx form any help in forward :)
Mocks are used to record invocations on objects for further verification or to provide values when called (later behavior requires setup).
In your SaveAndLoadEntity method you make calls to mock (Add and FindBy). Since mock is a fake object with no real behavior, those calls do nothing (they don't save nor extract any entities to/from database).
If you want to test persistence layer you should be doing tests against real database instance (or optionally, in-memory one).
// [Test] attribute is not needed
protected T SaveAndLoadEntity<T>(T entity) where T : BaseEntity
{
var dataSource = new DataSource("connection string");
dataSource.Add(entity);
var fromDb = dataSource.FindBy(entity.Id);
return fromDb;
}
At the moment you are making calls to not-setup mock which doesn't achieve anything.
Thank you jimmy_keen.
I change my code according to your advice like this and it worked great :)
[TestFixture]
public class PersistenceTest
{
protected ISession Session;
protected ITransaction Transaction;
[SetUp]
public void SetUp()
{
var helper = new NHibernateHelper("...connectionString....");
Session = helper.SessionFactory.OpenSession();
Transaction = Session.BeginTransaction();
}
protected T SaveAndLoadEntity<T>(T entity) where T : BaseEntity
{
Session.Save(entity);
Transaction.Commit();
var fromDb = Session.Get<T>(entity.Id);
return fromDb;
}
}
How do I create unit test with context based on integration component?
I have identified problem as the Extension is trying to resolve implementation and returning error message:
"Object reference not set to an instance of an object."
My class:
public sealed class GetListOfServiceIdsToProcess
{
public InOutArgument<IArguments> Arguments { get; set; }
protected override void Execute(CodeActivityContext context)
{
// I am recieving my error exception here
context.GetExtension<lib.Extension.MyExtenstion>();
var targetIds= (List<int>)Settings.Get("targetIds");
var wfa = this.Arguments.Get(context);
wfa.ListTargetIds = targetIds;
Arguments.Set(context, wfa);
}
}
My Test so far:
I have problem with implementation of the test as far i could get it:
/// <summary>
///A test for Execute
///</summary>
[TestMethod()]
public void ExecuteTest()
{
// create Isettings mock to return collection of service ids
var expected = new List<int>() { 30, 20 };
var wfaInput = new TestWorkFlow();
var serviceIdList = new GetListOfServiceIdsToProcess();
var wfParam = new Dictionary<string, object>();
wfParam.Add("WorkFlowArguments", wfaInput);
var results = WorkflowInvoker.Invoke(serviceIdList, wfParam);
var wfaResult = (IWorkFlowArguments)results["WorkFlowArguments"];
Assert.AreEqual(expected, wfaResult.ListOfServiceIdsToProcess);
}
Instead of using the static WorkflowInvoker.Invoke() new up a WorkflowInvoker instance and add a mock, or whatever is needed for your test, lib.Extension.MyExtenstion to the Extensions collection.
[TestMethod]
public void ExecuteTest()
{
// ...
var invoker = new WorkflowInvoker(activityToTest);
// This way your extension will be available during execution
invoker.Extensions.Add(new MyExtension());
var results = invoker.Invoke(inputArgs);
// ....
}
I have run through multiple options and the problem what I have is MS Workflow.
I have extracted all logic away from workflow code activity into separate class and this class has been put under tests.
This is the best I could do for this. As I have base classes, that are injected, but I could not easily implement what I needed.
Thank you all for help anyway.
I've got the following code and I need help to write a unit test for it. I'm using Moq library.
Here's the deal. I have a business class with a dependency to a repository (interface), so I can use it to save my entities to the database. My entity is basically a list of strings. The method AddAndSave, from MyBusinessClass, grab the value it receives as a parameters, put it into the list and call Save method from IRepository. Then, I clear the list of my entity. The code below show this example (I've made it simple so I can explain it here).
There's a unit test, too.
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
namespace TestesGerais
{
public class MyEntity
{
public MyEntity()
{
MyList = new List<string>();
}
public List<string> MyList { get; set; }
}
public interface IRepository
{
void Save(MyEntity entity);
}
public class MyBusinessClass
{
public IRepository Repository { get; set; }
private MyEntity _entity = new MyEntity();
public void AddAndSave(string info)
{
_entity.MyList.Add(info);
Repository.Save(_entity);
_entity.MyList.Clear(); // for some reason I need to clear it
}
}
[TestClass]
public class UnitTest10
{
[TestMethod]
public void TestMethod1()
{
var mock = new Mock<IRepository>();
MyBusinessClass b = new MyBusinessClass() { Repository = mock.Object };
b.AddAndSave("xpto");
mock.Verify(m => m.Save(It.Is<MyEntity>(x => x.MyList[0] == "xpto")), Times.Exactly(1));
}
}
}
My unit-test check if the IRepository's Save method was called with its parameter (an entity) having one element in the list, and having the value "xpto" in this element.
When I run this test, it turns red with the error message "Test method TestesGerais.UnitTest10.TestMethod1 threw exception:
System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index".
Ok, this is caused by the list that has been cleaned. If I comment the line "_entity.MyList.Clear();", everything goes well.
My question is: how can I test this without commenting the "Clear" line in my business class, and making sure that my repository's method is called passing the specific value (entity with one element with value "xpto")?
Thanks
I've changed my unit test using the Callback feature of Moq. This way, I can setup the mock so when AddAndSave is called, the parameter it receives is saved into a variable from my unit test, and I can assert it later.
[TestMethod]
public void TestMethod1()
{
var mock = new Mock<IRepository>();
string result = string.Empty;
mock.Setup(m => m.Save(It.IsAny<MyEntity>())).Callback((MyEntity e) => { result = e.MyList[0]; });
MyBusinessClass b = new MyBusinessClass() { Repository = mock.Object };
b.AddAndSave("xpto");
Assert.AreEqual(result, "xpto");
}
You could split your method up a bit. "AddAndSave" isn't all it does. You could then just test the behaviour of the adding and saving bit in isolation.
I am trying to test that the property gets it's value from the return of a Service call, but I am having trouble mocking the service call.
Here is my property:
public ICountry Country
{
get
{
if (_country == null)
{
ICountryService countryService = new CountryService();
_country = countryService.GetCountryForCountryId(_address.CountryId);
}
return _country;
}
}
Here is my attempt at testing this:
[TestMethod]
public void Country_should_return_Country_from_CountryService()
{
const string countryId = "US";
_address.CountryId = countryId;
var address = MockRepository.GenerateStub<Address>(_address);
var country = MockRepository.GenerateMock<ICountry>();
var countryService = MockRepository.GenerateStub<ICountryService>();
countryService.Stub(x => x.GetCountryForCountryId(countryId)).IgnoreArguments().Return(country);
Assert.AreEqual(address.Country, country);
}
I keep getting an error because the real countryService is being called, not my mock. I am using MsTest and Rhino Mocks. What am I doing wrong?
You problem is that the property is directly constructing the dependency. Due to this the mock service is not getting called, the actual real CountryService implementation is getting called.
A way around this might be to utilize constructor injection of a CountryService factory (or the service itself) in the other objects (Address?) constructor. This way you could get your fake CountryService (the mock) to be returned and be the one called by the method
For example:
private ICountryService _countryService;
//constructor
public OuterObject(ICountryService countryService)
{
//maybe guard clause
_countryService = countryService;
}
public ICountry Country
{
get
{
if (_country == null)
{
_country = _countryService.GetCountryForCountryId(_address.CountryId);
}
return _country;
}
}
You would need to then pass the mocked ICountryService into the other objects constructor in your unit test