Welcome to Typemock Answers. Here you can ask and receive answers from other community members. And if you liked or disliked an answer or thread: react with an up- or downvote Enjoy!

How to make a mocked object return another mocked object?

0 votes
I'm trying to make a mocked object ( HttpWebRequest.GetResponse() ) return another mocked object ( HttpWebResponse ). and I'm getting:
TypeMock.TypeMockException: 
*** No method GetResponse in type System.Net.HttpWebRequest returns TypeMock.MockObject
   at TypeMock.Mock.a(String A_0, Object A_1, Boolean A_2, Boolean A_3, Int32 A_4, Type[] A_5)
   at TypeMock.Mock.ExpectAndReturn(String method, Object ret, Int32 timesToRun, Type[] genericTypes)
   at TypeMock.Mock.ExpectAndReturn(String method, Object ret, Type[] genericTypes)
   at SI.Swiftbit.P2p.Tests.TrackerClientTest.TestNormalGetPeers() in c:\Documents and Settings\SpookyET\My Documents\Visual Studio 2005\Projects\SI.Swiftbit\SI.Swiftbit.P2p.Tests\TrackerClientTest.cs:line 138


For this code:

#region Using Directives

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Web;
using System.Text;
using NUnit.Framework;
using TypeMock;
using SI.Swiftbit.P2p;
using SI.Swiftbit.P2p.Utilities;

#endregion

namespace SI.Swiftbit.P2p.Tests
{
   [TestFixture]
   public class TrackerClientTest
   {
      TrackerClient trackerClient;
      Mock httpWebRequest;
      Mock httpWebResponse;
      byte[] filesKey = Encoding.UTF8.GetBytes("files");
      byte[] completeSourcesKey = Encoding.UTF8.GetBytes("complete");
      byte[] incompleteSourcesKey = Encoding.UTF8.GetBytes("incomplete");
      byte[] downloadedKey = Encoding.UTF8.GetBytes("downloaded");
      byte[] nameKey = Encoding.UTF8.GetBytes("name");
      
      [SetUp]
      public void Initialize()
      {
         MockManager.Init();
         httpWebRequest = MockManager.Mock(typeof(HttpWebRequest));
         httpWebResponse = MockManager.Mock(typeof(HttpWebResponse));
         trackerClient = new TrackerClient(
            new Uri("http://announce.com:6969/announce"));
      }
      
      [TearDown]
      public void Dispose()
      {
         MockManager.Verify();
      }
      
      [Test]
      public void TestNormalGetPeers()
      {
         PeersInfo peersInfo;
         Peer[] peers;
         SortedDictionary<byte[], object> responseData =
            new SortedDictionary<byte[], object>(new ByteArrayComparer());
         
         
         List<SortedDictionary<byte[], object>> peersList =
            new List<SortedDictionary<byte[], object>>();
         
         SortedDictionary<byte[], object> peer1 =
            new SortedDictionary<byte[], object>(new ByteArrayComparer());
         
         SortedDictionary<byte[], object> peer2 =
            new SortedDictionary<byte[], object>(new ByteArrayComparer());
         
         byte[] peerId1 = new byte[20]
         {
            1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
         };
         
         byte[] peerId2 = new byte[20]
         {
            4, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
         };
         
         byte[] infoKeyHash = new byte[20]
         {
            7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
         };
         
         string warningMessage = "This is a tracker warning.";
         
         peer1.Add(Encoding.UTF8.GetBytes("peer id"), peerId1);
         peer1.Add(
            Encoding.UTF8.GetBytes("ip"),
            Encoding.UTF8.GetBytes("1.1.1.1"));
         
         peer1.Add(Encoding.UTF8.GetBytes("port"), 6969);
         
         peer2.Add(Encoding.UTF8.GetBytes("peer id"), peerId2);
         peer2.Add(
            Encoding.UTF8.GetBytes("ip"),
            Encoding.UTF8.GetBytes("2.2.2.2"));
         
         peer2.Add(Encoding.UTF8.GetBytes("port"), 7000);
         
         responseData.Add(Encoding.UTF8.GetBytes("interval"), 5);
         responseData.Add(Encoding.UTF8.GetBytes("min interval"), 2);
         responseData.Add(Encoding.UTF8.GetBytes("complete"), 10);
         responseData.Add(Encoding.UTF8.GetBytes("incomplete"), 20);
         responseData.Add(
            Encoding.UTF8.GetBytes("warning message"),
            warningMessage);
         
         responseData.Add(Encoding.UTF8.GetBytes("peers"), peersList);
         
         httpWebRequest.ExpectAndReturn(
            "GetResponse",
            httpWebResponse,
            null);
         
asked Jul 26, 2005 by Dog_Soldier (680 points)

15 Answers

0 votes
Hi,
You need to return an instance of the real object (that is mocked) and not the Mock object (which is actually used to control the mocked instance).

For example:
   Mock httpWebRequest = MockManager.Mock(typeof(HttpWebRequest));
   Mock httpWebResponseMock = MockManager.Mock(typeof(HttpWebResponse));
   // create instance to return
   HttpWebResponse httpWebResponse = new HttpWebResponse();

   httpWebRequest.ExpectAndReturn(
      "GetResponse",
      httpWebResponse);


or as a shorthand, use MockObject
   Mock httpWebRequest = MockManager.Mock(typeof(HttpWebRequest));
   MockObject httpWebResponseMock = MockManager.MockObject(
             typeof(HttpWebResponse));
   // get mocked instance to return
   HttpWebResponse httpWebResponse = 
            (HttpWebResponse)httpWebResponseMock.Object ;

   httpWebRequest.ExpectAndReturn(
      "GetResponse",
      httpWebResponse);
answered Jul 26, 2005 by scott (29,080 points)
0 votes
I tried this, but it says that it can't find the constructor:

      [SetUp]
      public void Initialize()
      {
         MockManager.Init();
         httpWebRequest = MockManager.MockAll(typeof(HttpWebRequest));
         httpWebResponse = MockManager.MockObject(
            typeof(HttpWebResponse),
            Constructor.NotMocked,
            new SerializationInfo(typeof(byte), new FormatterConverter()),
            new StreamingContext(StreamingContextStates.All));
         
         trackerClient = new TrackerClient(
            new Uri("http://announce.com:6969/announce"));
      }
answered Jul 26, 2005 by Dog_Soldier (680 points)
0 votes
I don't know how to mock these two objects. I tried multiple things. Nothing seems to work. I'm using the BETA by the way.
answered Jul 26, 2005 by Dog_Soldier (680 points)
0 votes
Hi,

Hi,
1. Did you try mocking the constructor?
2. Try the following:
   Mock httpWebRequest = MockManager.Mock(typeof(HttpWebRequest));
   Mock httpWebResponseMock = MockManager.Mock(typeof(HttpWebResponse));
   // create instance to return
   HttpWebResponse httpWebResponse = 
      new HttpWebResponse(new SerializationInfo(typeof(byte), 
       new FormatterConverter()),
       new StreamingContext(StreamingContextStates.All)););

   httpWebRequest.ExpectAndReturn(
      "GetResponse",
      httpWebResponse); 
answered Jul 26, 2005 by scott (29,080 points)
0 votes
Normally, one would use the WebRequest.Create() method to create the object. I need both of them mocked.

         httpWebRequest.ExpectAndReturn(
            "GetResponse",
            httpWebResponse,
            null);
         
         httpWebResponse.ExpectAndReturn(
            "GetResponseStream",
            new MemoryStream(BEncoding.Encode(responseData))); 
answered Jul 26, 2005 by Dog_Soldier (680 points)
0 votes
I tried this, but it says that "Create" isn't getting called, which I don't understand since it does get called.

webRequestMock = MockManager.MockAll(typeof(WebRequest));
webRequestInstanceMock = MockManager.MockObject(typeof(WebRequest));
webResponseMock = MockManager.MockObject(typeof(WebResponse));

webRequestMock.ExpectAndReturn(
   "Create",
   (WebRequest) webRequestInstanceMock.Object);

webRequestInstanceMock.ExpectAndReturn(
   "GetResponse",
   (WebResponse) webResponseMock.Object,
   null);

webResponseMock.ExpectAndReturn(
    "GetResponseStream",
    new MemoryStream(BEncoding.Encode(responseData)));
answered Jul 26, 2005 by Dog_Soldier (680 points)
0 votes
Hi,
I see that you are using MockAll and MockObject.
webRequestMock = MockManager.MockAll(typeof(WebRequest));
webRequestInstanceMock = MockManager.MockObject(typeof(WebRequest));


When you use MockAll and Instance Mock, the expectations of MockAll are triggered only for All instances that are NOT specifically mocked.
i.e. if:
webRequestMock.ExpectAndReturn(
   "Create",
   (WebRequest) webRequestInstanceMock.Object);

webRequestInstanceMock.ExpectAndReturn(
   "GetResponse",
   (WebResponse) webResponseMock.Object,
   null); 

And you create a new instance - "Create" is not mocked, only "GetResponse", for all OTHER instances one "Create" is expected.
answered Jul 26, 2005 by scott (29,080 points)
0 votes
I want this method to access the mocks. I tried both MockAll and Mock. I thought that I can mock the static Create method to return an instance mock of WebRequest.

private byte[] ReadResponse(string requestUri)
{
   HttpWebRequest httpWebRequest = (HttpWebRequest) WebRequest.Create(
      requestUri);

   MemoryStream memoryStream = new MemoryStream();
   int byteRead;

   using (HttpWebResponse httpWebResponse =
         (HttpWebResponse) httpWebRequest.GetResponse())
   {
      using (Stream stream = httpWebResponse.GetResponseStream())
      {
         while (true)
         {
            byteRead = stream.ReadByte();

            if (byteRead == -1)
            {
               break;
            }

            memoryStream.WriteByte((byte) byteRead);
         }
      }
   }

   return memoryStream.ToArray();
}
answered Jul 26, 2005 by Dog_Soldier (680 points)
0 votes
Hi,

Well, actually the BEST way to test this is using the SWAP ARGUMENT feature - but this is only in the Enterprise Edition.
you would use:
    Mock mockControl = MockManager.Mock(typeof(YourClass));
    mockControl.ExpectUnmockedConstructor().Args(new Assign("file:\\\"+assemblyPath+"\test.html"));

You can then put a test.html in your test project.

:arrow: I haven't tried this, but I think that the Create is called on WebRequest.
The way TypeMock works is that only the actual type is mocked and not the derived types, so try mocking WebRequest.Create

(We are actually thinking of ways to implement this feature but it turns out to have quite complex scenarios, that can make using TypeMock even harder to understand).
answered Jul 26, 2005 by scott (29,080 points)
0 votes
The way TypeMock works is that only the actual type is mocked and not the derived types, so try mocking WebRequest.Create


I thought that is what I did.

// Mock TYPE WebRequest
webRequestMock = MockManager.Mock(typeof(WebRequest));

// Mock INSTANCE WebRequest
webRequestInstanceMock = MockManager.MockObject(typeof(WebRequest));

// Mock INSTANCE WebResponse
webResponseMock = MockManager.MockObject(typeof(WebResponse));

// MOCK TYPE WebRequest::Create() to return INSTANCE WebRequest
webRequestMock.ExpectAndReturn(
   "Create",
   (WebRequest) webRequestInstanceMock.Object);

// MOCK INSTANCE WebRequest.GetResponse() to RETURN INSTANCE WebResponse
webRequestInstanceMock.ExpectAndReturn(
   "GetResponse",
   (WebResponse) webResponseMock.Object,
   null);

// MOCK INTANCE WebResponse.GetResponseStream() to return a stream
webResponseMock.ExpectAndReturn(
    "GetResponseStream",
    new MemoryStream(BEncoding.Encode(responseData)))


So, you are saying that the INSTANCES are not being mocked because they are casted to HttpWebRequest and HttpWebResponse? That makes sense, because they virtual methods are overriden. I'm trying to mock instances of HttpWebRequest/HttpWebResponse, but I can't figure out how to invoke that constructor. I keep getting MissingMethodException.

If you were to add support for this, I think that you should try to make it transparent.
answered Jul 26, 2005 by Dog_Soldier (680 points)
...