I have a method that i want to mock that takes an array as a argument. In a real call, the method would modify this array and the resultant array would be use further along in code.
What i tried to do was pass in array to the mocked method call, that had values that would be valid when the array is used again. However what i find is when the call is being made to the mocked method it doesn't use the array i have specfied when setting up the mock, instead using the original array, Is there a way around this problem.
e.g
public interface ITest
{
int Do(int[] values);
}
public void MyTest
{
var testMock = new Mock<ITest>();
int[] returnArray = new int[] {1,2,3};
testMock.Setup(x => x.Do(returnArray)).Returns(0);
MyTestObject obj = new MyTestObject();
obj.TestFunction(testMock.Object);
}
public class MyTestObject
{
.....
public void TestFunction(ITest value)
{
int [] array = new int[3];
value.Do(array);
if (array[0] == 1)
This is where my test falls down as array is still the null array declared two lines above and not the array i specified in the mocked method call. Hope this explains what i am trying to achieve and if so is there anyway of doing it. Would also be open to using RhinoMocks as well if it could be done that way.
Thank in advance,
Kev
The only thing you have done here is to set up an expectation that your Do method will be called with returnArray as parameter, and that it will return 0 as the result. What you want to do is to
create a strict mock to better see what is being executed
setup a call that expects your initial array, and then runs a delegate to set the values to 1, 2, 3
using Rhino Mock this would look like this (using moq it will be equivalent):
private delegate int DoDelegate(int[] values);
[Test]
public void MyTest()
{
var testMock = MockRepository.GenerateStrictMock<ITest>();
testMock.Expect(x => x.Do(null))
.IgnoreArguments()
.Do(new DoDelegate(delegate(int[] values)
{
values[0] = 1;
values[1] = 2;
values[2] = 3;
return 0;
}));
//Execution (use your real object here obviously
int[] array = new int[3];
testMock.Do(array);
Assert.AreEqual(1, array[0]);
}
Related
I have the following method I wish to unit test:
public class Board
{
public static BoardElement RandomElement(List<BoardElement> elements)
{
int index = Random.Next(elements.Count);
return elements[index];
}
}
This method calls Random.Next(elements.Count).
I tried to create a mock of Random so that Random.Next(int maxValue) returns a controlled integer regardless of the int maxValue passed:
Random.Setup(random => random.Next(It.IsAny<int>())).Returns(randomInt);
The whole test function is as follows:
[Theory]
[MemberData(nameof(TestData.RandomElement_TestData), MemberType = typeof(TestData))]
private static void Test_RandomElement(List<BoardElement> elements, int randomInt)
{
Mock<Random> Random = new Mock<Random>();
Random.Setup(random => random.Next(It.IsAny<int>())).Returns(randomInt);
BoardElement element = Board.RandomElement(elements);
Assert.Equal(elements[randomInt], element);
}
Is there a way to setup Random.Next to return a controlled integer regardless of where it is called?
Here is my main class which I want to test. It contains one private method.
Public class MyClass
{
private bool IsWorkDone(MyItem item, string name)
{
using (MyThing thingObj = new MyThing(item.ID))
{
using (MyWork workObj = thingObj.Open())
{
try
{
return false;
}
}
}
return true;
}
}
In my test class I have written below method
public void CheckIsWorkDoneTest()
{
using (ShimsContext.Create())
{
MyItem myitem = new ShimMyItem () {
itemGet = () => new ShimMyItem () {
IDGet = () => new Guid();
}
};
ShimMyClass.AllInstances.isWorkDoneItemString = (MyClass, MyItem, MyName) => "Here I'm stuck. I need help from stackoverflow users"
PrivateObject objMyClass = new PrivateObject(typeof(MyClass));
object[] parameters = new object[2] { myItem, workName };
bool result = Convert.ToBoolean(objMyClass.Invoke("IsWorkDone", parameters));
Assert.AreEqual(result,true);
}
}
I want to set the value for oSite object from statement => "using (MyThing thingObj = new MyThing(item.ID)) " from my main MyClass Class.
while debugging this line throws Object reference not set to an instance error.
So using ShimMyClass.Allinstance how can I get or set the value for it?
You have quite a few inconsistencies, so your problem is probably just straitening them out. If you're actual code is more consistent, then update your post. The main things
You show private method IsComplete but call isWorkflowCompleted from your Invoke method
You probably end up calling your shimmed method that will pass "Here I'm stuck" and try to convert that string to a Boolean.
I fudged your skeleton and got mine to work after adjusting some of the names.
I have a method (method1) that I'd like to test, which based on parameters provided creates an object and calls another method (method2). So I'm mocking method2, which accepts an object (sampleObj).
public void method1(booleanParam) {
if(booleanParam){
List<SampleObj> fooList = new ArrayList<SampleObj>;
fooList.add(new SampleObj("another param"));
anotherService.method2(fooList);
}
//some other smart logic here
}
And here's my test with same obfuscated names (sorry if I missed any typo):
public void testMethod1() {
AnotherService mockedAnotherService = PowerMockito.mock(AnotherService.class);
ServicesFactory.getInstance().setMock(AnotherService.class, mockedAnotherService);
List<SampleObj> fooList = new ArrayList<SampleObj>;
fooList.add(new SampleObj("another param"));
// assert and verify
service.method1(true);
Mockito.verify(mockedAnotherService, times(1)).method2(fooList);
}
The problem is, when I try to mock the anotherService, I need to pass an object to method2, so I have to create a new one. But since it's a new object, it's not the same object, which will be passed from inside the method1, hence the test fails with the exception:
Argument(s) are different! Wanted:
anotherService.method2(
[com.smart.company.SampleObj#19c59e46]
);
-> at <test filename and line # here>
Actual invocation has different arguments:
anotherService.method2(
[com.smart.company.SampleObj#7d1a12e1]
);
-> at <service filename and line # here>
Any ideas how to accomplish that?
You have a few options:
Implement equals and hashCode on SampleObj. Because you didn't wrap fooList in a matcher, Mockito checks with List.equals, which checks equals for corresponding objects in each List. The default behavior of Object.equals is that a.equals(b) iff a == b--that is, objects are equal iff they refer to the same instance--but you're welcome to override that if every SampleObj("foobar") equals every other SampleObj("foobar").
Use a Hamcrest Matcher you write.
private static Matcher<List<SampleObj>> isAListWithObjs(String... strings) {
return new AbstractMatcher<List<SampleObj>>() {
#Override public boolean matches(Object object) {
// return true if object is a list of SampleObj corresponding to strings
}
};
}
// in your test
verify(mockedAnotherService).method2(argThat(isAnObjListWith("another param")));
Note that you could also just make a Matcher of a single SampleObj, and then use a Hamcrest wrapper like hasItem. See more matchers here.
Use a Captor to check equals your own way:
public class YourTest {
// Populated with MockitoAnnotations.initMocks(this).
// You can also use ArgumentCaptor.forClass(...), but with generics trouble.
#Captor ArgumentCaptor<List<SampleObj>> sampleObjListCaptor;
#Test public void testMethod1() {
// ...
verify(mockedAnotherService).method2(sampleObjListCaptor.capture());
List<SampleObj> sampleObjList = sampleObjListCaptor.getValue();
assertEquals(1, sampleObjList.size());
assertEquals("another param", sampleObjList.get(0).getTitle());
}
I'm using google mock framework to perform some unit tests over my code. I have a class named SerialPortManager with the constructor:
SerialPortManager(SerialPortFactoryInterface* serialPortFactory,SerialParserInterface* serialParsers[PORT_COUNT]);
To perform the tests I have the following test fixture
class SerialPortManagerTest: public testing::Test {
protected:
SerialPortManager* manager;
MockSerialPortFactory *portFactory;
SerialParserInterface *parsers[PORT_COUNT];
virtual void SetUp() {
portFactory = new MockSerialPortFactory();
for (int i = 0; i < PORT_COUNT; i++) {
parsers[i] = new MockSerialParser();
}
manager = 0;
}
Now, on one of my tests I need to set an expectation on one of the mocked SerialParsers. I try to do it as
EXPECT_CALL(*parsers[0], GetPendingCommands()).Times(1);
But I get
Method 'gmock_GetPendingCommands' could not be resolved
¿Is there a way to cast the SerialParserInterface pointer to the mocked type?
Solved by casting the argument of the constructor. I declare the parser array as MockSerialParser *parsers[PORT_COUNT], I instantiate the array objects as MockSerialParser * and then I pass the array to the constructor as manager = new SerialPortManager(portFactory,(SerialParserInterface**)parsers);
Using Moq, I want to Setup() a call, so that it always returns null, regardless of any supplied parameters.
I do it like this:
_myMock.Setup(mock => mock.MyMethod(
It.IsAny<int?>(),
It.IsAny<String>(),
It.IsAny<String>(),
It.IsAny<String>())).
Returns((IList<Item>)null
);
Quite lenghty for just returning null. Can I make it simpler?
Just don't make the setup, with the default MockBehavior.Loose it will return default values - null for classes, 0 for numbers, the default value for structs.
Caveat: if the return type is IEnumerable or Array, it will return and empty set, not null. In that case, you need an explicit setup.
It's very strange that it does not return empty IList though, as IList is IEnumerable. Probably it's a bug, but anyway, works for what you asked for :)
Both these examples work (using also FluentAssertions and NUnit, besides Moq):
public interface ISomeDummy
{
IList<int> Nums(int i);
}
[Test]
public void NullSetupTestWithMockOf()
{
var mock = Mock.Of<ISomeDummy>();
var items = mock.Nums(1);
items.Should().BeNull();
}
[Test]
public void NullSetupTestWithoutSetup()
{
var mock = new Mock<ISomeDummy>();
var items = mock.Object.Nums(1);
items.Should().BeNull();
}
No, you can't. Your method requires four parameters, so you gotta supply them.