How to use Moq to Verify that PropertyChanged is invoked with the expected object and property name? - unit-testing

Using NUnit and Moq, I'd like to replace the PropertyChanged handler code in the following test by Moq if it makes the test shorter and clearer. I'm currently unclear as to how to do this in Moq, verifying that PropertyChanged is invoked once for IsDirty and once for LocalDatabaseFilePath, each time with the expected object (o in the code). Can anybody advise how to do this with Moq please?
[Test]
[Category("Fast Tests")]
[Category("PropertyChanged Events")]
public void FactoryResetCommand_AllPropertiesChangedInViewModel_PropertyChangedEventsFiredAsExpected()
{
// Arrange
string expectedLocalDatabaseFilePath = "eldfp";
string otherLocalDatabaseFilePath = "other" + expectedLocalDatabaseFilePath;
Mock<IDataStoreSettingsDataModel> stubDataModel = new Mock<IDataStoreSettingsDataModel>();
stubDataModel.Setup(x => x.LocalDatabaseFilePath).Returns(expectedLocalDatabaseFilePath);
IDataStoreSettingsViewModel sutViewModel = new DataStoreSettingsViewModel(
stubDataModel.Object,
ReportExceptionAsync);
sutViewModel.LocalDatabaseFilePath = otherLocalDatabaseFilePath;
sutViewModel.IsDirty = false;
// I'd like to replace the following by Moq if shorter/clearer
int propertyChangedCountIsDirty = 0;
int propertyChangedCountLocalDatabaseFilePath = 0;
object? objIsDirty = null;
object? objLocalDatabaseFilePath = null;
sutViewModel.PropertyChanged += ((o, e) =>
{
switch (e?.PropertyName)
{
case nameof(DataStoreSettingsViewModel.IsDirty):
objIsDirty = o;
++propertyChangedCountIsDirty;
break;
case nameof(DataStoreSettingsViewModel.LocalDatabaseFilePath):
objLocalDatabaseFilePath = o;
++propertyChangedCountLocalDatabaseFilePath;
break;
}
});
// I'd like to replace the above by Moq if shorter/clearer
// Act
if (sutViewModel.FactoryResetCommand.CanExecute(null))
sutViewModel.FactoryResetCommand.Execute(null);
// Assert
Assert.AreEqual(1, propertyChangedCountIsDirty);
Assert.AreEqual(1, propertyChangedCountLocalDatabaseFilePath);
Assert.AreSame(sutViewModel, objIsDirty);
Assert.AreSame(sutViewModel, objLocalDatabaseFilePath);
}

Worked it out myself.
After adding the following interface:
public interface IPropertyChangedEventHandler
{
void PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e);
}
The test using Moq looks like this:
[Test]
[Category("Fast Tests")]
[Category("PropertyChanged Events")]
public void FactoryResetCommand_AllPropertiesChangedInViewModel_PropertyChangedEventsFiredAsExpected()
{
// Arrange
string originalLocalDatabaseFilePath = "oldfp";
string otherLocalDatabaseFilePath = "other" + originalLocalDatabaseFilePath;
Mock<IPropertyChangedEventHandler> mockPropertyChangedEventHandler = new Mock<IPropertyChangedEventHandler>();
Mock<IDataStoreSettingsDataModel> stubDataModel = new Mock<IDataStoreSettingsDataModel>();
stubDataModel.Setup(x => x.LocalDatabaseFilePath).Returns(originalLocalDatabaseFilePath);
IDataStoreSettingsViewModel sutViewModel = new DataStoreSettingsViewModel(
stubDataModel.Object,
ReportExceptionAsync);
sutViewModel.LocalDatabaseFilePath = otherLocalDatabaseFilePath;
sutViewModel.IsDirty = false;
sutViewModel.PropertyChanged += mockPropertyChangedEventHandler.Object.PropertyChanged;
// Act
if (sutViewModel.FactoryResetCommand.CanExecute(null))
sutViewModel.FactoryResetCommand.Execute(null);
// Assert
mockPropertyChangedEventHandler.Verify(x => x.PropertyChanged(sutViewModel,
It.Is<System.ComponentModel.PropertyChangedEventArgs>(e => e.PropertyName == nameof(DataStoreSettingsViewModel.IsDirty))),
Times.Once);
mockPropertyChangedEventHandler.Verify(x => x.PropertyChanged(sutViewModel,
It.Is<System.ComponentModel.PropertyChangedEventArgs>(e => e.PropertyName == nameof(DataStoreSettingsViewModel.LocalDatabaseFilePath))),
Times.Once);
}

Related

Unit Testing: Verify that a method was called, without testing frameworks like Mockito or MockK

Not using testing frameworks like MockK or Mockito seems to be becoming more and more popular. I decided to try this approach. So far so good, returning fake data is simple. But how do I verify that a function (that does not return data) has been called?
Imagine having a calss like this:
class TestToaster: Toaster {
override fun showSuccessMessage(message: String) {
throw UnsupportedOperationException()
}
override fun showSuccessMessage(message: Int) {
throw UnsupportedOperationException()
}
override fun showErrorMessage(message: String) {
throw UnsupportedOperationException()
}
override fun showErrorMessage(message: Int) {
throw UnsupportedOperationException()
}
}
With MockK I would do
verify { toaster.showSuccessMessage() }
I do not want to reinvent a wheel so decided to ask. Finding anything on Google seems to be very difficult.
Since this is a thing, I assume the point would be to totally remove mocking libraries and everything can be done without them.
The old school way to do it before any appearance of the mocking library is to manually create an implementation that is just for testing . The test implementation will store how an method is called to some internal state such that the testing codes can verify if a method is called with expected parameters by checking the related state.
For example , a very simple Toaster implementation for testing can be :
public class MockToaster implements Toaster {
public String showSuccesMessageStr ;
public Integer showSuccesMessageInt;
public String showErrorMessageStr;
public Integer showErrorMessageInt;
public void showSuccessMessage(String msg){
this.showSuccesMessageStr = msg;
}
public void showSuccessMessage(Integer msg){
this.showSuccesMessageInt = msg;
}
public void showErrorMessage(String msg){
this.showErrorMessageStr = msg;
}
public void showErrorMessage(Integer msg){
this.showErrorMessageInt = msg;
}
}
Then in your test codes , you configure the object that you want to test to use MockToaster. To verify if it does really call showSuccessMessage("foo") , you can then assert if its showSuccesMessageStr equal to foo at the end of the test.
A lot of people seem to be suggesting the very straight forward solution for this, which totally makes sense. I decided to go a bit fancy and achieve this syntax:
verify(toaster = toaster, times = 1).showErrorMessage(any<String>()).
I created simple Matchers:
inline fun <reified T> anyObject(): T {
return T::class.constructors.first().call()
}
inline fun <reified T> anyPrimitive(): T {
return when (T::class) {
Int::class -> Int.MIN_VALUE as T
Long::class -> Long.MIN_VALUE as T
Byte::class -> Byte.MIN_VALUE as T
Short::class -> Short.MIN_VALUE as T
Float::class -> Float.MIN_VALUE as T
Double::class -> Double.MIN_VALUE as T
Char::class -> Char.MIN_VALUE as T
String:: class -> "io.readian.readian.matchers.strings" as T
Boolean::class -> false as T
else -> {
throw IllegalArgumentException("Not a primitive type ${T::class}")
}
}
}
Added a map to store call count for each method to my TestToaster where the key is the name of the function and value is the count:
private var callCount: MutableMap<String, Int> = mutableMapOf()
Whenever a function gets called I increase current call count value for a method. I get current method name through reflection
val key = object {}.javaClass.enclosingMethod?.name + param::class.simpleName
addCall(key)
In oder to achieve the "fancy" syntax, I created inner subcalss for TestToaster and a verify function:
fun verify(toaster: Toaster , times: Int = 1): Toaster {
return TestToaster.InnerToaster(toaster, times)
}
That function sends current toaster instance to the inner subclass to create new instance and returns it. When I call a method of the subclass in my above syntax, the check happens. If the check passes, nothing happens and test is passed, if conditions not met - and exception is thrown.
To make it more general and extendable I created this interface:
interface TestCallVerifiable {
var callCount: MutableMap<String, Int>
val callParams: MutableMap<String, CallParam>
fun addCall(key: String, vararg param: Any) {
val currentCountValue = callCount.getOrDefault(key, 0)
callCount[key] = currentCountValue + 1
callParams[key] = CallParam(param.toMutableList())
}
abstract class InnerTestVerifiable(
private val outer: TestCallVerifiable,
private val times: Int = 1,
) {
protected val params: CallParam = CallParam(mutableListOf())
protected fun check(functionName: String) {
val actualTimes = getActualCallCount(functionName)
if (actualTimes != times) {
throw IllegalStateException(
"$functionName expected to be called $times, but actual was $actualTimes"
)
}
val callParams = outer.callParams.getOrDefault(functionName, CallParam(mutableListOf()))
val result = mutableListOf<Boolean>()
callParams.values.forEachIndexed { index, item ->
val actualParam = params.values[index]
if (item == params.values[index] || (item != actualParam && isAnyParams(actualParam))) {
result.add(true)
}
}
if (params.values.isNotEmpty() && !result.all { it } || result.isEmpty()) {
throw IllegalStateException(
"$functionName expected to be called with ${callParams.values}, but actual was with ${params.values}"
)
}
}
private fun isAnyParams(vararg param: Any): Boolean {
param.forEach {
if (it.isAnyPrimitive()) return true
}
return false
}
private fun getActualCallCount(functionName: String): Int {
return outer.callCount.getOrDefault(functionName, 0)
}
}
data class CallParam(val values: MutableList<Any> = mutableListOf())
}
Here is the complete class:
open class TestToaster : TestCallVerifiable, Toaster {
override var callCount: MutableMap<String, Int> = mutableMapOf()
override val callParams: MutableMap<String, TestCallVerifiable.CallParam> = mutableMapOf()
override fun showSuccessMessage(message: String) {
val key = object {}.javaClass.enclosingMethod?.name + message::class.simpleName
addCall(key, message)
}
override fun showSuccessMessage(message: Int) {
val key = object {}.javaClass.enclosingMethod?.name + message::class.simpleName
addCall(key, message)
}
override fun showErrorMessage(message: String) {
val key = object {}.javaClass.enclosingMethod?.name + message::class.simpleName
addCall(key, message)
}
override fun showErrorMessage(message: Int) {
val key = object {}.javaClass.enclosingMethod?.name + message::class.simpleName
addCall(key, message)
}
private class InnerToaster(
verifiable: TestCallVerifiable,
times: Int,
) : TestCallVerifiable.InnerTestVerifiable(
outer = verifiable,
times = times,
), Toaster {
override fun showSuccessMessage(message: String) {
params.values.add(message)
val functionName = object {}.javaClass.enclosingMethod?.name + message::class.simpleName
check(functionName)
}
override fun showSuccessMessage(message: Int) {
params.values.add(message)
val functionName = object {}.javaClass.enclosingMethod?.name + message::class.simpleName
check(functionName)
}
override fun showErrorMessage(message: String) {
params.values.add(message)
val functionName = object {}.javaClass.enclosingMethod?.name + message::class.simpleName
check(functionName)
}
override fun showErrorMessage(message: Int) {
params.values.add(message)
val functionName = object {}.javaClass.enclosingMethod?.name + message::class.simpleName
check(functionName)
}
}
companion object {
fun verify(toaster: Toaster, times: Int = 1): Toaster {
return InnerToaster(toaster as TestCallVerifiable, times)
}
}
}
I have not tested this extensively and it will evolve with time, but so far it works well for me.
I also wrote an article about this on Medium: https://sermilion.medium.com/unit-testing-verify-that-a-method-was-called-without-testing-frameworks-like-mockito-or-mockk-433ef8e1aff4

PHPUnit: how to mock multiple method calls with multiple arguments and no straight order?

I need to test following function:
[...]
public function createService(ServiceLocatorInterface $serviceManager)
{
$firstService = $serviceManager->get('FirstServiceKey');
$secondService = $serviceManager->get('SecondServiceKey');
return new SnazzyService($firstService, $secondService);
}
[...]
I know, I might test it this way:
class MyTest extends \PHPUnit_Framework_TestCase
{
public function testReturnValue()
{
$firstServiceMock = $this->createMock(FirstServiceInterface::class);
$secondServiceMock = $this->createMock(SecondServiceInterface::class);
$serviceManagerMock = $this->createMock(ServiceLocatorInterface::class);
$serviceManagerMock->expects($this->at(0))
->method('get')
->with('FirstServiceKey')
->will($this->returnValue($firstService));
$serviceManagerMock->expects($this->at(1))
->method('get')
->with('SecondServiceKey')
->will($this->returnValue($secondServiceMock));
$serviceFactory = new ServiceFactory($serviceManagerMock);
$result = $serviceFactory->createService();
}
[...]
or
[...]
public function testReturnValue()
{
$firstServiceMock = $this->createMock(FirstServiceInterface::class);
$secondServiceMock = $this->createMock(SecondServiceInterface::class);
$serviceManagerMock = $this->createMock(ServiceLocatorInterface::class);
$serviceManagerMock->expects($this->any())
->method('get')
->withConsecutive(
['FirstServiceKey'],
['SecondServiceKey'],
)
->willReturnOnConsecutiveCalls(
$this->returnValue($firstService),
$this->returnValue($secondServiceMock)
);
$serviceFactory = new ServiceFactory($serviceManagerMock);
$result = $serviceFactory->createService();
}
[...]
Both workes fine, but if I swap the ->get(xxx) lines in the createService function, both tests will fail.
So, how do I have to change the testcases which doesn't need a specific sequenz for the parameters 'FirstServiceKey', 'SecondServiceKey, ...
You can try with willReturnCallback or willReturnMap strategy, as example of willReturnCallback:
public function testReturnValue()
{
$firstServiceMock = $this->createMock(FirstServiceInterface::class);
$secondServiceMock = $this->createMock(SecondServiceInterface::class);
$serviceManagerMock = $this->createMock(ServiceLocatorInterface::class);
$serviceManagerMock->expects($this->any())
->method('get')
->willReturnCallback(
function ($key) use($firstServiceMock, $secondServiceMock) {
if ($key == 'FirstServiceKey') {
return $firstServiceMock;
}
if ($key == 'SecondServiceKey') {
return $secondServiceMock;
}
throw new \InvalidArgumentException; // or simply return;
}
);
$serviceFactory = new ServiceFactory($serviceManagerMock);
$result = $serviceFactory->createService();
}
Hope this help
It's been a while and so there is a new option to solve this: Change to 'Prophets'
public function testReturnValue()
{
$this->container = $this->prophesize(ServiceLocatorInterface::class);
$firstService = $this->prophesize(FirstServiceInterface::class);
$secondService = $this->prophesize(SecondServiceKey::class);
$this->container->get('FirstServiceKey')->willReturn(firstService);
// And if you like
$this->container->get('FirstServiceKey')->shouldBeCalled();
$this->container->get('SecondServiceKey')->willReturn(secondService);
[...]
$serviceFactory = new ServiceFactory();
/*
* Little error in my example. ServiceLocatorInterface is parameter of
* createService() and not the constructor ;) (ZF2/3)
*/
$result = $serviceFactory->createService(
$this->container->reveal()
);
[...]
}
and now, it doesn't matter, in which sequence you'll make the '$serviceManager->get([...]);' calls \o/

How to break dependency on StreamReader's readLine() method in microsoft fakes unit testing?

Here is my code in one of the method which I want to test:
using (var sr = new StreamReader(myFile))
{
string line;
while ((line = sr.ReadLine()) != null)
{
if (line.Equals("completed"))
{
continue; //here it is getting called infinite times
}
if(line.Equals("processed"))
{
break;
}
}
}
In my test method I have written below code with the help of shim:
ShimStreamReader.ConstructorString = delegate (StreamReader #this, string #string)
{
var reader = new ShimStreamReader(#this);
reader.ReadLine = () =>
{
return "completed";
};
};
Now I dont want to pass the file. Instead I want to pass the stream of characters or string.
Above test code is calling and breaking the dependency of new StreamReader(myFile) as expected and entering into while loop.
As soon as it is entering it in while loop, sr.ReadLine() is returning "completed" all the time. So I'm stuck here. How would I stop here or how would I write the input string so that as soon as my first call return completed in second call of sr.ReadLine() it should return null, and then breaks the loop?
You're more into a general coding question here rather than fakes. All you need to do is add a flag and set it when you're ready to end the input. This is the code I used
private bool _lineSent = false;
[TestMethod]
public void ReaderTest()
{
using (ShimsContext.Create())
{
ShimStreamReader.ConstructorString = (reader, s) =>
{
ShimStreamReader shimReader = new ShimStreamReader(reader);
shimReader.ReadLine = () =>
{
if (!_lineSent)
{
_lineSent = true;
return "completed";
}
else
{
return null;
}
};
};
ClassToTest testInstance = new ClassToTest();
testInstance.ReadStream();
}
}
By the way, depending on your level and what you are trying to learn, you might want to look into dependency injection and using stubs rather then shims. Shims are handy and nice, but for new development and code under your control, try to use stubs.

Error "Expected invocation on the mock once, but was 0 times" when unit testing with moq

I have the following class I want to test:
public interface ISqlServiceByModule
{
DataSet GetPagedAggregateData(int clientId, int moduleId, int billTypeId, PagedTable result);
}
public class IncidentModuleService : IIncidentModuleService
{
private readonly ISqlServiceByModule sqlServiceByModule;
public IncidentModuleService(ISqlServiceByModule sqlServiceByModule)
{
if (sqlServiceByModule == null) throw new ArgumentNullException("sqlServiceByModule");
// Inject the ISqlServiceByModule dependency into the constructor
this.sqlServiceByModule = sqlServiceByModule;
}
public PagedTable GetData(int clientId, int moduleId, int billTypeId, Dictionary<string, string> queryStringParameters)
{
PagedTable result = new PagedTable(queryStringParameters);
DataSet dataSet = this.sqlServiceByModule.GetPagedAggregateData(clientId, moduleId, billTypeId, result);
// Map the DatSet to a PagedTable
if (dataSet == null || dataSet.Tables.Count == 0)
{
result.SetPagesFromTotalItems(0);
}
else
{
result.SetPagesFromTotalItems(Convert.ToInt16(dataSet.Tables[1].Rows[0][0]));
result.Listings = dataSet.Tables[0];
}
return result;
}
}
Specifically, I want to test the GetData method. My unit test looks like this:
[TestClass]
public class IncidentModuleServiceUnitTest
{
private DataSet incidentsData;
[TestInitialize]
public void SetUp()
{
this.incidentsData = new DataSet();
}
[TestMethod]
public void GetDataTestGetPagedAggregateDataIsCalled()
{
//-- Arrange
int billTypeId = 1;
int clientId = 1;
int moduleId = 1;
Dictionary<string, string> queryStringParameters = new Dictionary<string,string>();
PagedTable tempResult = new PagedTable(queryStringParameters);
DataSet dataSet = new DataSet();
dataSet.Tables.Add(new DataTable());
var mockSqlService = new Mock<ISqlServiceByModule>();
mockSqlService.Setup(r => r.GetPagedAggregateData(clientId, moduleId, billTypeId, tempResult)).Returns(this.incidentsData);
IncidentModuleService target = new IncidentModuleService(mockSqlService.Object);
//-- Act
var actual = target.GetData(clientId, moduleId, billTypeId, queryStringParameters);
//-- Assert
Assert.IsNull(actual.Listings);
mockSqlService.Verify(r => r.GetPagedAggregateData(clientId, moduleId, billTypeId, tempResult), Times.Once);
}
}
The error I am getting happens on the last line:
mockSqlService.Verify(r => r.GetPagedAggregateData(clientId, moduleId, billTypeId, tempResult), Times.Once);
And the exact error message is this:
{"\r\nExpected invocation on the mock once, but was 0 times: r =>
r.GetPagedAggregateData(.clientId, .moduleId, .billTypeId, .tempResult
Configured setups:\r\nr => r.GetPagedAggregateData(.clientId,
.moduleId, .billTypeId, .tempResult),
Times.Never
Performed invocations:\r\nISqlServiceByModule.GetPagedAggregateData(1,
1, 1, PagedTable)"}
Any idea why this is happening? It looks to me like the method in question is being called, but Moq doesn't like the parameters for some reason, even though they are the exact same ones in all three invocations, as far as I can tell.
PagedTable is a reference type not a value type. Therefore the parameters in Setup don't match what was called even though they look like they should be the same. You could use It.IsAny<PagedTable>() instead of tempResult.
See this answer for an example of how to check that the PagedTable parameter was the correct one.

unit test - mockito testing to check if another method is invoked

Summary: I am trying to test if a method is invoked once I call one method.
What this class does is, displays information of wrong spelled words and provides u with buttons to 'ignore' or 'ignore all' or 'add to dictionary', etc.
Over here 'ignore' is a JButton declared above.
I am trying to write one test for this method ->
public class SpellCheckerDialog extends JDialog implements ActionListener {
...
..
public void actionPerformed( ActionEvent ev ) {
Object source = ev.getSource();
if( source == ignore ) {
searchNext();
}
}
...
}
Here is what it is invoking, I am testing to see if this method is being invoked or not.
...
//inside same class
public boolean searchNext() {
String wordStr;
while( true ) {
wordStr = tok.nextInvalidWord();
if( wordStr == null ) {
dispose();
String title = SpellChecker.getApplicationName();
if(title == null){
title = this.getTitle();
}
SpellChecker.getMessageHandler().handleInformation( getParent(), title, Utils.getResource( "msgFinish" ) );
return false;
}
if( ignoreWords.contains( wordStr ) ) {
continue;
}
String changeTo = changeWords.get( wordStr );
if( changeTo != null ) {
replaceWord( wordStr, changeTo );
continue;
}
break;
}
word.setText( wordStr );
notFound.setText( wordStr );
List<Suggestion> list = dictionary.searchSuggestions( wordStr );
boolean needCapitalization = tok.isFirstWordInSentence() && Utils.isFirstCapitalized( wordStr );
Vector<String> suggestionsVector = new Vector<String>();
for( int i = 0; i < list.size() && i < options.getSuggestionsLimitDialog(); i++ ) {
Suggestion sugestion = list.get( i );
String newWord = sugestion.getWord();
if( needCapitalization ) {
newWord = Utils.getCapitalized( newWord );
}
if( i == 0 )
word.setText( newWord );
suggestionsVector.add( newWord );
}
suggestionsList.setListData( suggestionsVector );
addToDic.setEnabled( true );
return true;
}
What I have tried until now, tried using Mockito and calling the verify method, but this code snippet seems to not working or have lots of dependencies that I am struggling to get around.
Inside my TestClass, I have this - >
Dialog fr = Mockito.mock(Dialog.class);
SpellCheckerDialog sD = new SpellCheckerDialog(fr);
sD.searchNext();
Mockito.verify(sD, Mockito.times(1)).thenReturn(searchNext());
I don't know if I should be making a stub for my (ActionEvent ev) or ...
Verifications must be done on the mocks created by Mockito, because the framework can't possibly know what happens with objects that it does not manage. This being said, your searchNext() method is part of your class under test so you probably want to spy on it just like in the example below:
public class SpyTest {
class MyClass {
public void callDoSomething(){
doSomething();
}
public void doSomething(){
// whatever
}
}
#Test
public void shouldSpyAndVerifyMethodCall(){
MyClass objectUnderTest = new MyClass();
MyClass spy = Mockito.spy(objectUnderTest);
spy.callDoSomething();
Mockito.verify(spy, Mockito.times(1)).doSomething();
}
}
My advice is to go through the Mockito documentation and examples from the link above, as they're pretty straight-forward and should give you a good starting point.
EDIT as per your comment:
public class SpyTest {
class MyClass {
private JButton myButtton;
public void actionPerformed(ActionEvent event){
if(event.getSource() == myButtton) {
searchNext();
}
}
public void searchNext(){
// whatever
}
}
#Mock // define a mock for the button to "hack" the source check
private JButton mockButton;
#InjectMocks // inject the mock in our object under test
private MyClass objectUnderTest;
#Test
public void shouldSpyAndVerifyMethodCall(){
// spy on our object so we can query various interactions
MyClass spy = spy(objectUnderTest);
// event mock
ActionEvent mockEvent = mock(ActionEvent.class);
// "hack" the source check
when(mockEvent.getSource()).thenReturn(mockButton);
// call main logic
spy.actionPerformed(mockEvent);
// verify interactions
verify(spy).searchNext(); // times(1) not needed because it's the implicit/default setting, see David's comment
}
}