<?xml version="1.0" encoding="utf-8"?> <?xml-stylesheet type="text/css" href="http://www.sm-art.biz/Data/style/rss1.css" ?> <?xml-stylesheet type="text/xsl" href="http://www.sm-art.biz/Data/xsl/rss1.xsl" ?>
<!--RSS generated by mojoPortal Blog Module V 1.0 on Friday, October 10, 2008-->
<rss version="2.0">
  <channel>
    <title>Bloggin'bout Ivonna</title>
    <link>http://www.sm-art.biz/Default.aspx?pageid=9</link>
    <description>Tutorials and how-tos for Asp.Net automated testing</description>
    <copyright>Copyright 2008 by me</copyright>
    <ttl>120</ttl>
    <managingEditor>art@nospamsm-art.biz</managingEditor>
    <generator>mojoPortal Blog Module V 1.0</generator>
    <item>
      <title>Ivonna and test-driving AJAX applications</title>
      <link>http://www.sm-art.biz/ivonna-and-test-driving-ajax-applications.aspx</link>
      <pubDate>Fri, 20 Jun 2008 19:41:39 GMT</pubDate>
      <guid>f3e7b768-a3c9-4592-97d3-7ec4bbf29294</guid>
      <comments>http://www.sm-art.biz/ivonna-and-test-driving-ajax-applications.aspx</comments>
      <description><![CDATA[<p>Some people get nervous when they read that Ivonna doesn't support AJAX. I decided to clarify this issue.</p>
<p>The current version of Ivonna supports Ajax-enabled controld. It means that if you add an UpdatePanel, or even a TabContainer, to your page, nothing bad happens. There are some known problems, namely, if you place a password control inside a tab, its value won't get read on a postback. So, let's say that a TabContainer is <i>almost</i> supported.</p>
<p>Ivonna doesn't support callbacks. Everithing works like Ajax is not enabled. For example, if you have an UpdatePanel, and you disable partial endering, a callback will become a regular postback, and this is how Ivonna will treat the situation, regardless of the partial rendering enabled or not. In other words, you'll have the same results, except that the IsCallback property will be set to false.</p>
<p>If you want to develop some more sophisticated AJAX stuff and test it with Ivonna, I'll be happy to listen to your suggestions. Keep in mind, however, that most of it would be client-side scripts that are not in the Ivonna's domain.</p><br /><br />&nbsp;&nbsp;<a href='http://www.sm-art.biz/ivonna-and-test-driving-ajax-applications.aspx'>...</a>]]></description>
    </item>
    <item>
      <title>Testing: functional or unit?</title>
      <link>http://www.sm-art.biz/BlogView.aspx?pageid=9&amp;ItemID=2&amp;mid=8</link>
      <pubDate>Mon, 17 Mar 2008 08:38:43 GMT</pubDate>
      <guid>8b0efbda-d04d-46de-ad75-7f947774da36</guid>
      <comments>http://www.sm-art.biz/BlogView.aspx?pageid=9&amp;ItemID=2&amp;mid=8</comments>
      <description><![CDATA[<p>It is widely known that you can't unit test Asp.Net applications. That is, unless you use the new MVC model, which is still under construction. Even with MVC, you can't test the view, and you usually don't have to, since you make it as simple as possible.</p>
<p>There are numerous reasons for that. First, you just can't fake any depedencies. You can't do dependency injection: the View's constructor should be parameterless (unless you provide your own PageFactory, but that's a different story), and you can't avoid calling the ProcessRequest method. In short, you are not in the control. Once you have created a page, it's in the hands of the Asp.net runtime, which mercifully lets you handle a couple of events, but only in the production code. Second, you just can't take an instance and do various things you want to test.</p>
<p>That's not mentioning the fact that everithing's happening in a different process.</p>
<p>As a result, people tend to move all code to other places, where it can be tested. I do agree&nbsp; that often it's good to make your view thinner. But you have to be careful and not move the code that belongs there. For example reading the control values from another class makes it too coupled to the view, and doesn't improve testability. On the other hand, sometimes you can't avoid complicated event handlers coupled to page controls. For example, consider a handler of the repeater's RowDataBound event, where you have to retrieve the row's grandparent control, find a particular label inside it, and assign a particular value to it. You can't test it, so you have to manually debug it.</p>
<p>With Ivonna, it's different. First, you run all your code in the same process. Second, you can hook into the running code and change stuff to meet your needs. And third, you have TypeMock at your hands, so that you can mock the stuff you can't change manually.</p>
<p>You still have to design for testability though. It won't work with dropping a table from the Server Explorer. You'll have to deal with SqlClient intrinsics in order to figure out which method to mock and what to return. So you'll have to improve your design skills a bit.</p>
<p>Consider displaying a set of database records. In a strongly coupled version you can use an ObjectDataSource, for example, and hardcode some model class as its data source. The model itself doesn't know about the Web and resides in a separate project. That's why it is convenient to mock it: we mock the boundary between our layers. We could mock the Select method of the ObjectDataSource, but then we wouldn't be sure that it calls our model, so part of our UI layer would remain untested.</p>
<p>So, what we do it setup a mock controller for the model class and setup the return values for its select method, all that before we get the page. Then investigate the table and test the values. Still, it looks like an integration test. So, we can test two things: that the grid's&nbsp; is set to the ID of our ObjectDataSource, and that ObjectDataSource retrieves the correct values. How do we do that?</p>
<ol>
    <li>Handle the PageInit method</li>
    <li>Inside the handler, evaluate the DataSourceID property of our grid. That's test one.</li>
    <li>Still inside the handler, find the ObjectDataSource instance using FindControl()</li>
    <li>Manually invoke the Select method and check the result.</li>
</ol>
<p>Handling the Init event can be done via the WebRequest object. In cases like that, it is not enough to call session.GetPage() to retrieve a page. You have to prepare the request, get the responce using session.ProcessRequest(), and get the Page property.</p>
<p>The decoupled scenario is, as always, more complicated. You might want to assign the data source directly in your code, but you probably have an interface that incapsulates your model. However, whatever architecture you are using, you still have to instantiate a real model class and wire up all your dependencies. So, you can either mock the model class as in the previous example, or mock the class that does the actual instantiation and return a fake model instance. The second option lets you use a fake model provided by TypeMock, any other mock framework, or created manually, while the first option still uses the real model class with all relevant methods intercepted and providing mock results.</p><br /><br />&nbsp;&nbsp;<a href='http://www.sm-art.biz/BlogView.aspx?pageid=9&ItemID=2&mid=8'>...</a>]]></description>
    </item>
    <item>
      <title>Overview of Ivonna </title>
      <link>http://www.sm-art.biz/BlogView.aspx?pageid=9&amp;ItemID=1&amp;mid=8</link>
      <pubDate>Thu, 28 Feb 2008 15:31:04 GMT</pubDate>
      <guid>7aa8c477-d081-45aa-ab4e-39556fa4c7a1</guid>
      <comments>http://www.sm-art.biz/BlogView.aspx?pageid=9&amp;ItemID=1&amp;mid=8</comments>
      <description><![CDATA[<p>Many developers recently discovered that the Test Driven Development (TDD) process improves the development process significantly. While testability is relatively easy in the desktop world, Web applications are not so easily tested. One of the problems is that a Web application runs in a different process, making it impossible to communicate with the test code. As a result, what we are testing is a raw Html output, rather than the application's internals. Another problem is that it is very difficult to put a Web application into a special environment that is more suitable for testing. For example, we cannot check the behaviour of the system when a database is unavailable, unless we manually stop the server. <br />
<br />
Several Asp.Net frameworks exist, but they are either parsing the Html output and recreating the structure of the page (<a href="http://nunitasp.sourceforge.net/">NUnitAsp</a>), or test the client-side functionality (<a href="http://selenium.openqa.org">Selenium</a> and <a href="http://watin.sourceforge.net">WatiN</a>). Another framework, Plazma, hosts the Asp.Net engine so that it is executed in the test runner process; however, due to the engine's inherent untestability we are still unable to test, let alone mock, the page's intrinsics. As a result, we can write integration, but not unit, tests. For example, to verify that a certain label displays the user's name, we have to add a user to our database, navigate to the login page, enter the user's credentials, navigate to the page being tested, parse the output in order to find a span with a certain ID, and check the span's inner text. Oh, and don't forget to delete the user at the end of the test. <br />
<br />
With Ivonna, it is different. You are programming in a way similar to desktop testing. You setup your mocks, in this case, mock the Membership service, then you request a page (you have a &quot;real&quot; instance of the Page class, not the raw Html), find the label you need and check its Text property. But there's more: you can run asserts not only against the response, but also during the page's lifecycle. For example, you can add a Page_Init handler and verify the label's initial value or visibility. You can also run tests against concrete page classes (for example, if you want to test a page-specific method) or App_Code classes. Just step into the request like described above, and run your test. <br />
<br />
Note that Ivonna doesn't require a Web server.</p><br /><br />&nbsp;&nbsp;<a href='http://www.sm-art.biz/BlogView.aspx?pageid=9&ItemID=1&mid=8'>...</a>]]></description>
    </item>
  </channel>
</rss>