I've started unit testing the first time. I'm following tutorials of resoCoder
here is my test code where I'm mocking my dbManager class but I could not mock DAO's as they are auto-generated in moor and there is no setter method for them.
class MockDbManager extends Mock implements DbManager{}
void main() {
RecipeLocalDataSource dataSource;
MockDbManager _dbManager;
setUp(() {
_dbManager = MockDbManager();
dataSource = RecipeLocalDataSource(_dbManager);
});
group('Search Food Table', (){
List<FoodTableData> getFoodTable(){
var list = [];
for(var i =1; i <=5 ; i++){
list.add(FoodTableData(id: i, name: 'item $i'));
}
return list;
}
var searchQuery = 'query';
test('Should return foodTableData when query is successful', (){
//arrange
when(_dbManager.foodTableDao.searchFoods(searchQuery)).thenAnswer((realInvocation) async => getFoodTable());
//act
var result = dataSource.searchFoodTable('test');
//assert
verify(_dbManager.foodTableDao.searchFoods(searchQuery));
expect(getFoodTable(), result);
});
});
}
I'm getting the following error
NoSuchMethodError: The method 'searchFoods' was called on null.
Receiver: null
Tried calling: searchFoods("query")
I understood the error but don't know how to solve that.
Also, I'm getting a similar issue with preferenceManager class as well, where I'm having a getter for UserPrefs.
UserPrefs get user => UserPrefs(_pref);
when I'm accessing _prefManager.user.name for the test, it throws the same error. How can I tackle that as well?
I believe you're missing a level of mocking, leading to the null exception. Keep in mind the mocked class returns null for everything. You have to provide values for everything.
You've mocked DbManager, but not the foodTableDao field inside DbManager.
// I don't have your classes, so these are just my guesses at matching their interface
abstract class TableDao {
String searchFoods();
}
abstract class DbManager {
TableDao foodTableDao;
}
class MockDbManager extends Mock implements DbManager {}
class MockTableDao extends Mock implements TableDao {}
// ↑ Define this mocked class as well
void main() {
test('Mockito example', () {
final dbManager = MockDbManager();
final mockTableDao = MockTableDao();
// ↑ instantiate this mocked class which will be a field value inside dbManager
// Mock the field access for dbManager.foodTableDao
when(dbManager.foodTableDao).thenReturn(mockTableDao);
// ↑ You're missing this ↑ level of stubbing, so add this
when(mockTableDao.searchFoods()).thenAnswer((realInvocation) => 'Cucumber');
// ↑ define the stubbing at the mockTableDao level, not dbManger.mockTableDao.searchFoods
expect(dbManager.foodTableDao.searchFoods(), 'Cucumber');
// You can use foodTableDao field here, getting the mocked value as expected
});
}
In your example above, you can't access dbManager.foodTableDao to set up a mock for dbManager.foodTableDao.searchFoods(), because dbManager.foodTableDao is null until you mock it. So this line:
when(_dbManager.foodTableDao.searchFoods(searchQuery)).thenAnswer((realInvocation) async => getFoodTable());
was throwing the null exception, not the expect test below. (The expect test was never reached.)
The issue with _prefManager.user.name is the same I'm guessing. You need to mock User class and provide a when/return of MockUser for _prefManager.user in order to provide another level of when/return for _prefManager.user.name.
It's like Mockception... you need to go another level deeper in your mocks. ;)
Related
I'm using TDD approach with xUnit 2, NSubstitute, AutoFixture, FluentAssertions for my unit tests.
I want test my service method which using FluentValidation.
Simple example:
Validator:
RuleSet("Nulls", () =>
{
RuleFor(viewModel => viewModel).NotNull();
});
My service(under test):
if(Validate(viewModel, "Nulls"))
//....
private bool Validate(AddMerchantViewModel viewModel, string option)
{
var result = _merchantValidator.Validate(viewModel, ruleSet: options);
return result.IsValid;
}
And my unit test:
I don't know how to mock the merchantValidator.Validate result.
[Theory, AutoNSubstituteData]
public void Add_ViewModelAsNull_ShouldThrowArgumentNullException(
AbstractValidator<AddMerchantViewModel> merchValidator,
MerchantsService service)
{
// Arrange
//here I don't know how to mock result of Validate. It is always null.
merchantValidator.Validate(Arg.Any<AddMerchantViewModel>(), ruleSet: Arg.Any<string>()).Return(new ValidationResult());
// Act
Action action = () => service.Add(null);
// Assert
action.ShouldThrow<ArgumentNullException>();
}
By default AutoFixture creates a new instance of a type every time it's requested. In this particular case the AbstractValidator<AddMerchantViewModel> type is instantiated twice - as the merchValidator parameter and as a dependency of the MerchantsService class.
As a result the configured validator is not used by the service. In order to fix that you should decorate the merchValidator parameter with the [Frozen] attribute so that the same instance of the AbstractValidator<AddMerchantViewModel> type is always returned by AF:
[Theory, AutoNSubstituteData]
public void Add_ViewModelAsNull_ShouldThrowArgumentNullException(
[Frozen]AbstractValidator<AddMerchantViewModel> merchValidator,
MerchantsService service)
// ...
More info abot the [Frozen] attribute can be found here.
say I have two models that extend from Eloquent and they relate to each other. Can I mock the relationship?
ie:
class Track extends Eloquent {
public function courses()
{
return $this->hasMany('Course');
}
}
class Course extends Eloquent {
public function track()
{
return $this->belongsTo('Track');
}
}
in MyTest, I want to create a mock of course, and return an instance of track, by calling the track property, not the track instance (I don't want the query builder)
use \Mockery as m;
class MyTest extends TestCase {
public function setUp()
{
$track = new Track(array('title' => 'foo'));
$course = m::mock('Course[track]', array('track' => $track));
$track = $course->track // <-- This should return my track object
}
}
Since track is a property and not a method, when creating the mock you will need to override the setAttribute and getAttribute methods of the model. Below is a solution that will let you set up an expectation for the property you're looking for:
$track = new Track(array('title' => 'foo'));
$course = m::mock('Course[setAttribute,getAttribute]');
// You don't really care what's returned from setAttribute
$course->shouldReceive('setAttribute');
// But tell getAttribute to return $track whenever 'track' is passed in
$course->shouldReceive('getAttribute')->with('track')->andReturn($track);
You don't need to specify the track method when mocking the Course object, unless you are also wanting to test code that relies on the query builder. If this is the case, then you can mock the track method like this:
// This is just a bare mock object that will return your track back
// whenever you ask for anything. Replace 'get' with whatever method
// your code uses to access the relationship (e.g. 'first')
$relationship = m::mock();
$relationship->shouldReceive('get')->andReturn([ $track ]);
$course = m::mock('Course[track]');
$course->shouldReceive('track')->andReturn($relationship);
I have a class that I want to write unit tests for. I'm using StructureMap (2.6.3) in the project and I have some problems with that.
For testing I use Nunit (2.6.0.12054) and RhinoMocks (3.6).
Normally i inject my dependencies in the constructor of my classes and then it's easy to substitute the dependencies with mocks in my unit tests. But there are a few cases where I can't do that, where I have no control over when the class under test is created. In these cases I use ObjectFactory.GetInstance() to get the dependencies.
public class MyClass
{
public int MyMethod(string parameter)
{
var myDependency = ObjectFactory.GetInstance<IMyDependency>();
try
{
return myDependency.CalculateValue(parameter);
}
catch (Exception ex)
{
//Suppress exception.
return 0;
}
}
}
For this class and method I want to write two tests. First I want to to test that the dependency is called and the value it calculates is returned by the class under test. Second, the dependency might throw an exception and I want to test that this exception is suppressed by the class under test and that it return zero in that case.
[TestFixture]
public class MyClassTests()
{
[Test]
public void MyMethod_DependencyReturnsValue_ReturnsValueFromDependency
{
//Arrange.
const int valueFromDependencyStub = 333;
var myDependencyStub = MockRepository.GenerateStub<IMyDependency>();
myDependencyStub.Stub(x => x.CalculateValue()).Return(valueFromDependencyStub);
ObjectFactory.Inject<IMyDependency>(myDependencyStub);
var target = new MyClass();
//Act.
var result = target.MyMethod("test");
//Assert.
Assert.AreEqual(valueFromDependencyStub, result);
}
[Test]
public void MyMethod_DependencyThrowsException_ReturnsZero
{
//Arrange.
var myDependencyStub = MockRepository.GenerateStub<IMyDependency>();
myDependencyStub.Stub(x => x.CalculateValue()).Throw(new Exception());
ObjectFactory.Inject<IMyDependency>(myDependencyStub);
var target = new MyClass();
//Act.
var result = target.MyMethod("test");
//Assert.
Assert.AreEqual(0, result);
}
}
Both these tests work if I run them individually, but if I run the both it does not work. I my real case the second test, where the stubbed dependency throws an exception, runs first. When the other test runs the stubbed dependency still throws an exception.
The problem, as I understand it, is that I'm using the global ObjectFactory and inject my stub into that. That would probably work if I could clear the ObjectFactory after each test, but I found no way to do that. ObjectFactory.EjectAllInstancesOf() sounded like something that would work, but it doesn't.
How do I solve this? Either by changing my test or by actually rewriting the class under test.
I'm following the accepted answer in this question but I'm getting a NullReferenceException.
What I need is having a partial mock stub a property (both getter and setter) to behave like a stub (as a simple automatic property). Currently I am able to stub the getter but not the setter.
Is this possible?
EDIT: this is a simple example, I hope it helps explaining my problem.
public class SomeClass
{
public virtual string SomeProperty
{
get{ return SomeMethodDependingOnDBOrAspSession(); }
set{ SomeMethodDependingOnDBOrAspSession(value); } // I want to avoid calling this setter implementation
}
}
var partialMock = MockRepository.GeneratePartialMock<SomeClass>();
partialMock.Stub(p => p.SomeProperty); // I want SomeProperty to behave as an automatic property
When using a PartialMock you can get auto-implemented property like behavior by using PropertyBehavior feature of Rhino Mocks. Given the class in your question, the following nunit test passes for me.
[Test]
public void TestPartialMock()
{
var someClass = MockRepository.GeneratePartialMock<SomeClass>();
someClass.Stub(x => x.SomeProperty).PropertyBehavior();
string val = "yo!";
Assert.DoesNotThrow(() => someClass.SomeProperty = val);
Assert.AreEqual(val, someClass.SomeProperty);
}
If you don't need a PartialMock you could use a Stub which has property behavior by default. You'd simply replace the first two lines of the test with:
var someClass = MockRepository.GenerateStub<SomeClass>();
using [assembly:InternalsVisibleTo()] and
public sealed class AppService
{
//TODO: fix dev's spelling
//want to test this
public AddSubscribtionResponse AddSubscribtion(AddSubscribtionRequest request)
{
return ExecuteQueryProc<AddSubscribtionResponse>("spAddAppToUserGroup", request).First();
}
//I want to stub or interaction test the call to here
#if DEBUG
internal
#endif
List<T> ExecuteQueryProc<T>(string query, object parameters = null)
{
var cn=GetConnection();
//DatabaseCommand is a static class =(
return DatabaseCommand.ExecuteQueryProc<T>(cn, query, parameters);
}
}
Every attempt I've made at getting Rhino to stub or intercept the Execute Query proc method has failed.
var service = MockRepository.GeneratePartialMock<AppService>(null);
service.Stub(f => f.ExecuteQueryProc<AddSubscribtionRequest>(null, null)).IgnoreArguments().Return(new List<AddSubscribtionRequest>());
var expected = new AddSubscribtionRequest();
var actual = service.AddSubscribtion(expected);
Throws
System.InvalidOperationException: ExecuteReader: CommandText property has not been initialized
Remove the "sealed" from your class (Rhino.Mocks can't proxy your class if it can't inherit from it). And ExecuteQueryProc has to be virtual to be able to stub its functionality.