<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://msmvps.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Angel "Java" Lopez : TDD, ASP.NET MVC</title><link>http://msmvps.com/blogs/lopez/archive/tags/TDD/ASP.NET+MVC/default.aspx</link><description>Tags: TDD, ASP.NET MVC</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP2 (Build: 40407.4157)</generator><item><title>Escribiendo una Aplicación usando TDD (Part 6) Modificando Vistas</title><link>http://msmvps.com/blogs/lopez/archive/2013/04/07/escribiendo-una-aplicaci-243-n-usando-tdd-part-6-modificando-vistas.aspx</link><pubDate>Sun, 07 Apr 2013 11:33:39 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1826752</guid><dc:creator>lopez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1826752</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2013/04/07/escribiendo-una-aplicaci-243-n-usando-tdd-part-6-modificando-vistas.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2011/06/27/writing_2D00_an_2D00_application_2D00_using_2D00_tdd_2D00_part_2D00_5_2D00_adding_2D00_views.aspx"&gt;Anterior Post&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;El post de hoy va a mostrar que, al haber usado MVC (Model-View-Controller) podemos modificar nuestras vistas, sin necesidad de tocar el código. Ni siquiera tenemos que recompilar, en muchos casos.&lt;/p&gt;  &lt;p&gt;Primero, una novedad: he pasado el ejemplo, paso a paso, a ASP.NET MVC 4, usando Visual Studio 2010. Y también lo pasé a mi cuenta de GitHub&lt;/p&gt;  &lt;p&gt;&lt;a href="https://github.com/ajlopez/TddAppAspNetMvc"&gt;https://github.com/ajlopez/TddAppAspNetMvc&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/apptdd0501.png" alt="" /&gt; &lt;/p&gt;  &lt;p&gt;Vean que cada versión (cada entrega por post) está señalada por tags. La de este post es la 0.0.5. Siempre pueden ver en&lt;/p&gt;  &lt;p&gt;&lt;a href="https://github.com/ajlopez/TddAppAspNetMvc/commits/master"&gt;https://github.com/ajlopez/TddAppAspNetMvc/commits/master&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/apptdd0504.png" alt="" /&gt; &lt;/p&gt;  &lt;p&gt;Una de las cosas nuevas que me dió esta versión de ASP.NET MVC es el soporte de Razor, ahora las vistas están escritas con Razor. Como en el anterior post, use los “wizard” de creación de vistas del propio Visual Studio, y luego las modifiqué un poco (apenas algun texto).&lt;/p&gt;  &lt;p&gt;En el paso de este post, lo que hice fue agregar &lt;a href="http://twitter.github.io/bootstrap/"&gt;Twitter Bootstrap&lt;/a&gt;:&lt;/p&gt;  &lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/apptdd0503.png" alt="" /&gt; &lt;/p&gt;  &lt;p&gt;Agregué estilos y javascript que necesita Bootstrap, y armé un _viewstart.chtml que le indica a Razor que todas las vistas usan un _Layout.cshtml&lt;/p&gt;  &lt;p&gt;Vean cómo se ve ahora la página de Subjects:&lt;/p&gt;  &lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/apptdd0502.png" alt="" /&gt; &lt;/p&gt;  &lt;p&gt;Notablemente, no toqué nada de código ni de tests. Esto muestra que hasta se puede trabajar en paralelo, o en distintos tiempos: primero se arma el código de los controladores y acciones con tests. Luego, al mismo tiempo o en algun momento, se agregan y mejoran las vistas.&lt;/p&gt;  &lt;p&gt;Próximos posts: agregar libros, aparición de primeros servicios, modelo de negocio, etc.&lt;/p&gt;  &lt;p&gt;Nos leemos!&lt;/p&gt;  &lt;p&gt;Angel “Java” Lopez   &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1826752" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Desarrollo+de+Software/default.aspx">Desarrollo de Software</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/C+Sharp/default.aspx">C Sharp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Desarrollo+Agil/default.aspx">Desarrollo Agil</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/TDD/default.aspx">TDD</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/ASP.NET+MVC/default.aspx">ASP.NET MVC</category></item><item><title>VAN en Alt.NET Hispano: Desarrollando una Aplicación con TDD</title><link>http://msmvps.com/blogs/lopez/archive/2012/06/18/van-en-alt-net-hispano-desarrollando-una-aplicaci-243-n-con-tdd.aspx</link><pubDate>Mon, 18 Jun 2012 16:29:07 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1811274</guid><dc:creator>lopez</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1811274</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2012/06/18/van-en-alt-net-hispano-desarrollando-una-aplicaci-243-n-con-tdd.aspx#comments</comments><description>&lt;p&gt;El sábado que viene, 23 de Junio, estaré en una VAN (reunión virtual) organizada por &lt;a href="http://altnethispano.org"&gt;el grupo Alt.NET Hispano&lt;/a&gt;, tratando el tema de cómo desarrollar una aplicación con TDD. El horario es el habitual 18pm GMT, en Buenos Aires tenemos GMT-3, y es 3 de la tarde hora local.&lt;/p&gt;  &lt;p&gt;Quiero mostrar cómo uso habitualmente TDD para ir desarrollando una aplicación. Usaré C#, una interfaz con ASP.NET MVC, y seguramente algún proyecto de clases donde ir poniendo el dominio. Estoy pensando más en detalle el dominio, quisiera uno que pudiera abarcar en las dos horas que tenemos disponibles, y que tuviera algunas reglas.&lt;/p&gt;  &lt;p&gt;Para mí, es muy importante usar TDD en código en producción. Me ha resultado muy útil, no sólo por la cobertura de tests que me permite refactorizar con confianza, sino por el proceso de diseño del código y de la aplicación en sí. En los últimos años le he agregado también la idea de que lo importante son los casos de uso, y darle menos peso a temas como el diseño de la base de datos que puede aparecer más adelante en un desarrollo ágil, no tiene por qué estar desde el principio.&lt;/p&gt;  &lt;p&gt;Ya escribí &lt;a href="http://msmvps.com/blogs/lopez/archive/tags/TDD/default.aspx"&gt;varios posts sobre desarrollo con TDD&lt;/a&gt; y mis proyectos personales públicos prácticamente están todos desarrollados con TDD (pueder ver mi &lt;a href="http://github.com/ajlopez"&gt;cuenta de GitHub&lt;/a&gt; cómo van avanzando test a test). Pero no había tenido la oportunidad de mostrar esta técnica en una VAN sobre una aplicación y un dominio. Espero que pueda mostrar qué bueno es aplicar TDD desde el comienzo, y cómo nos ayuda en un desarrollo ágil.&lt;/p&gt;  &lt;p&gt;Más información sobre Alt.NET Hispano en:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://altnethispano.org/Inicio.aspx"&gt;http://altnethispano.org/Inicio.aspx&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Sobre las reuniones VAN y cómo participar en:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://altnethispano.org/reuniones/descripcion.aspx"&gt;http://altnethispano.org/reuniones/descripcion.aspx&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Las anteriores VAN han sido publicadas (en video) en:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://altnethispano.org/reuniones/historico.aspx"&gt;http://altnethispano.org/reuniones/historico.aspx&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;El calendario de próximo eventos en:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://altnethispano.org/reuniones/calendario.aspx"&gt;http://altnethispano.org/reuniones/calendario.aspx&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Nos leemos!&lt;/p&gt;  &lt;p&gt;Angel “Java” Lopez   &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1811274" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Desarrollo+Agil/default.aspx">Desarrollo Agil</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/ALT.NET/default.aspx">ALT.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/TDD/default.aspx">TDD</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/ASP.NET+MVC/default.aspx">ASP.NET MVC</category></item><item><title>El Armado Agil de una Aplicación</title><link>http://msmvps.com/blogs/lopez/archive/2012/01/28/el-armado-agil-de-una-aplicaci-243-n.aspx</link><pubDate>Sat, 28 Jan 2012 17:34:09 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1805351</guid><dc:creator>lopez</dc:creator><slash:comments>3</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1805351</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2012/01/28/el-armado-agil-de-una-aplicaci-243-n.aspx#comments</comments><description>&lt;p&gt;En este nuevo año, estoy participando en la creación de una aplicación, en un equipo ágil, usando un Scrum-like (iteration reviews, planning, standups, iteration backlog, etc..). Tecnologías: .NET, C#, ASP.NET MVC, Azure, SQL Server, y más (en cualquier momento aparece JSON, REST, Javascript, jQuery, algún NoSQL, cache en memoria, etc…). Pero lo interesante de esta aplicación es que ha nacido prácticamente como “green field”. Si bien el proyecto completo tiene casi un año de existencia (y hasta tiene proyectos antecedentes que se remontan a 3 años atrás), la aplicación que le ha tocado a mi equipo es nueva: nace desde un File, New Project.&lt;/p&gt;  &lt;p&gt;El proyecto es privado, así que no hay repositorio público para mostrar avance. Pero quería comentar en este post algunas de las estrategias que estamos usando para avanzar en el proyecto.&lt;/p&gt;  &lt;p&gt;Primero: buscar basarnos en casos de uso. Anteriormente, el proyecto se basó demasiado (en mi parecer) en solucionar temas técnicos, sin llegar a hacer pie en lo que realmente se necesita. Entonces, desde la primera iteración (son semanales) nos concentramos en mostrar algo que funcione. Si bien hay varios riesgos técnicos a tomar en cuenta, no fueron (todavía) el centro de atención. Nos parece que para el cliente final lo mejor AHORA es mostrar algo andando, para que pueda explorar si es lo que necesita.&lt;/p&gt;  &lt;p&gt;Veamos un ejemplo de estrategia: en vez de modelar el dominio con persistencia en la base de datos, lo principal del mismo ESTA EN MEMORIA, en objetos que solamente viven en memoria: persistencia, concurrencia, transacciones no están en la agenda actual, porque por las características del sistema (disculpen no dar más detalles, es privado) NO SON EL TEMA a tratar AHORA. Es mejor explorar una base de solución ahora, que tener todas las piezas en su lugar.&lt;/p&gt;  &lt;p&gt;Como el cambio es constante (al aparecer nuevas historias, al reflexionar el cliente final sobre cómo quiere que quede el producto final, sus casos de uso), todo se ha ido construyendo con TDD (Test-Driven Development). El Code Coverage es &amp;gt; 85%, en general (incluido los controladores de vistas web, estamos usando ASP.NET MVC). Cuando hubo que cambiar algo en la segunda iteración (un refactor de los que yo llamo “quirúrgico”) todo esta en su lugar para que los tests nos ayudaran a comprobar que al cambiar la implementación interna todo siguiera funcionando como se esperaba.&lt;/p&gt;  &lt;p&gt;Otro ejemplo: esta semana pasada, gran parte del dominio paso a estar persistida en SQL Server (y en Azure SQL Server). El lunes completamos la implementación de almacenamiento/persistencia en esa tecnología, usando TDD, luego la inyectamos en los lugares apropiados, y prácticamente no se rompió ningún test. En la entrega del viernes, tenemos parte del dominio en memoria (para hacer cambios rápidos) y parte en SQL Server (para ir explorando algo más cercano al producto final). Pero estamos preparados para cambiar esa persistencia a Azure Table Storage, si hace falta, y por qué no, al nuevo DynamoDB de Amazon. El desarrollo ágil y TDD nos da el “courage” (coraje) de abrazar el cambio.&lt;/p&gt;  &lt;p&gt;TDD, en vez de ser un gasto de tiempo, es un gran avance: primero, nos sirve en el diseño de lo que implementamos. Luego, nos sirve en ir armando algo sin gastar tiempo en pruebas manuales o sesiones de depuración. Vamos avanzando de a “baby steps” (pasos de bebé): cada nueva característica se agrega con TDD, y la vamos integrando. Desplegamos en Azure más de una vez al día, para que el cliente final pueda ir viendo los avances. Las nuevas características se van anunciando en la lista del proyecto.&lt;/p&gt;  &lt;p&gt;Otro ejemplo: el jueves se comenzó a implementar temas de seguridad (autorización en particular, con usuarios y grupos). ¿Acaso implementamos eso usando alguna tecnología? ¿Fuimos e instalamos Azman o cualquier otra cosa? ¿Fuimos a usar Access Control System, tokens y claims? No. Armamos los tests e implementamos la lógica (permisos, reglas) en memoria. El viernes ya estaba listo para la demostración, con distintos usuarios (de nuevo, definidos en memoria). De ahora en más, podemos tener retroalimentación del cliente y usuarios finales, sobre qué es lo que funciona o no del “approach” que adoptamos. Sabemos que alguna parte de la implementación puede sufrir en escalabilidad. Es parte de lo que tenemos en el radar. Pero, como digo, “no cruzar el puente antes de llegar al puente”. No es (en este proyecto en particular, cada uno de Uds. analizará su caso y contexto) lo PRIORITARIO ahora. En vez de estar semanas viendo cómo implementar eso con Azman, o con claims, o lo que sea, ya en dos días tenemos algo funcionando, listo para refactorizar a tecnología PORQUE TENEMOS los tests.&lt;/p&gt;  &lt;p&gt;Claro que no todo tiene que ser un lecho de rosas. Pero, por lo menos yo, estoy muy contento y entusiasmado por este camino que tomamos. Espero que todo esto permita llevar a buen puerto un proyecto que ya lleva muchos meses dando vueltas.&lt;/p&gt;  &lt;p&gt;Nos leemos!&lt;/p&gt;  &lt;p&gt;Angel “Java” Lopez   &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1805351" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Scrum/default.aspx">Scrum</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Desarrollo+de+Software/default.aspx">Desarrollo de Software</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Desarrollo+Agil/default.aspx">Desarrollo Agil</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/TDD/default.aspx">TDD</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/ASP.NET+MVC/default.aspx">ASP.NET MVC</category></item><item><title>Escribiendo una Aplicación usando TDD (Part 5) Agregando Vistas</title><link>http://msmvps.com/blogs/lopez/archive/2011/06/27/writing_2D00_an_2D00_application_2D00_using_2D00_tdd_2D00_part_2D00_5_2D00_adding_2D00_views.aspx</link><pubDate>Mon, 27 Jun 2011 10:21:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1795259</guid><dc:creator>lopez</dc:creator><slash:comments>3</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1795259</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2011/06/27/writing_2D00_an_2D00_application_2D00_using_2D00_tdd_2D00_part_2D00_5_2D00_adding_2D00_views.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2011/06/02/writing_2D00_an_2D00_application_2D00_using_2D00_tdd_2D00_part_2D00_4_2D00_update_2D00_and_2D00_insert.aspx"&gt;Anterior Post&lt;/a&gt;     &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2013/04/07/escribiendo-una-aplicaci-243-n-usando-tdd-part-6-modificando-vistas.aspx"&gt;Pr&amp;oacute;ximo Post&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Ahora ya tengo algunos tests y en verde. Voy a agregar algunas vistas MVC en este paso de hoy. Pueden bajar el c&amp;oacute;digo desde mi &lt;a href="http://code.google.com/p/ajcodekatas/"&gt;AjCodeKatas Google Project&lt;/a&gt;, en trunk/AppTdd/Step04. As&amp;iacute; que este post tiene pocos nuevos tests: muestra que podemos agregar interfaz de usuario DESPUES de los tests, y (para destacar) SIN TENER una base de datos a&amp;uacute;n, ni siquiera una capa de servicios (&amp;ldquo;service layer&amp;rdquo;).&lt;/p&gt;
&lt;p&gt;Primero, agregu&amp;eacute; una master page Site.master y un estilo style.css (que tom&amp;eacute; de otro proyecto ASP.NET MVC 2)&lt;/p&gt;
&lt;p&gt;Agregu&amp;eacute; un nuevo controlador Home:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/apptdd0401.png" alt="" /&gt; &lt;/p&gt;
&lt;p&gt;Y usando el men&amp;uacute; de contexto sobre el m&amp;eacute;todo Index agregu&amp;eacute; una vista asociada al m&amp;eacute;todo:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/apptdd0402.png" alt="" /&gt; &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Modifiqu&amp;eacute; el c&amp;oacute;digo de la master page para tener una nueva opci&amp;oacute;n en el men&amp;uacute;:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/apptdd0403.png" alt="" /&gt; &lt;/p&gt;
&lt;p&gt;Entonces, agregu&amp;eacute; una vista, esta vez asociada al m&amp;eacute;todo Index del controlador Subject:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/apptdd0404.png" alt="" /&gt; &lt;/p&gt;
&lt;p&gt;Seleccion&amp;eacute; a &amp;ldquo;List&amp;rdquo; como &amp;ldquo;Vien Content&amp;rdquo;, y a &amp;ldquo;Subject&amp;rdquo; como el tipo a usar como base del modelo.&lt;/p&gt;
&lt;p&gt;Pero el m&amp;eacute;todo del controlador es:&lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; ActionResult Index()
{
    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; View(subjects);
}&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;Usa una lista de temas (&amp;ldquo;subjects&amp;rdquo;) que ha sido inyectada hasta ahora en un constructor por los tests:&lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; SubjectController(IList&amp;lt;Subject&amp;gt; subjects)
{
    &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.subjects = subjects;
}
&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;Pero esperen! Esa lista es inyectada por los tests. Ahora, necesito que est&amp;eacute; disponible en el proceso normal de un controlador. As&amp;iacute; que agregu&amp;eacute; un constructor sin par&amp;aacute;metros:&lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; SubjectController()
    : &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;(Domain.Instance.Subjects)
{
}
&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;El Domain.Instance es un dominio en memoria:&lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; Domain
{
    &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;static&lt;/span&gt; Domain instance = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Domain();
    &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; Domain()
    {
        &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Subjects = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; List&amp;lt;Subject&amp;gt;()
        {
            &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Subject() { Id = 1, Name = &amp;quot;&lt;span style="color:#8b0000;"&gt;Mathematics&lt;/span&gt;&amp;quot; },
            &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Subject() { Id = 2, Name = &amp;quot;&lt;span style="color:#8b0000;"&gt;Physics&lt;/span&gt;&amp;quot; },
            &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Subject() { Id = 3, Name = &amp;quot;&lt;span style="color:#8b0000;"&gt;Biology&lt;/span&gt;&amp;quot; },
            &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Subject() { Id = 4, Name = &amp;quot;&lt;span style="color:#8b0000;"&gt;Literature&lt;/span&gt;&amp;quot; }
        };
    }
    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;static&lt;/span&gt; Domain Instance { &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt; { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; instance; } }
    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; IList&amp;lt;Subject&amp;gt; Subjects { &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt;; &lt;span style="color:#0000ff;"&gt;set&lt;/span&gt;; }
}
&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;Ahora s&amp;iacute; el controlador de Subject puede manejar el m&amp;eacute;todo Index. Cambio enlaces en la vista que me agreg&amp;oacute; el wizard. Los cambio de:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/apptdd0406.png" alt="" /&gt; &lt;/p&gt;
&lt;p&gt;a que usen la propiedad Id como clave primaria:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/apptdd0407.png" alt="" /&gt; &lt;/p&gt;
&lt;p&gt;Este es el resultado:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/apptdd0405.png" alt="" /&gt; &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Cre&amp;eacute; entonces otras vistas, para los otros m&amp;eacute;todos del controlador Subject. Segu&amp;iacute; usando el wizard de Visual Studio &amp;ldquo;Add View &amp;hellip; &amp;ldquo;:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/apptdd0408.png" alt="" /&gt; &lt;/p&gt;
&lt;p&gt;Me encontr&amp;eacute; que me faltaban algunas acciones. Escrib&amp;iacute; una nueva:&lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; ActionResult Edit(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; id)
{
    var model = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.subjects.Where(s =&amp;gt; s.Id == id).FirstOrDefault();
    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; View(model);
}
&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;con tests! ;-)&lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;[TestMethod]
&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; GetSubjectForEdit()
{
    IList&amp;lt;Subject&amp;gt; subjects = GetSubjects();
    SubjectController controller = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; SubjectController(subjects);
    ActionResult result = controller.Edit(1);
    Assert.IsNotNull(result);
    Assert.IsInstanceOfType(result, &lt;span style="color:#0000ff;"&gt;typeof&lt;/span&gt;(ViewResult));
    ViewResult viewResult = (ViewResult)result;
    Assert.IsInstanceOfType(viewResult.ViewData.Model, &lt;span style="color:#0000ff;"&gt;typeof&lt;/span&gt;(Subject));
    Subject model = (Subject)viewResult.ViewData.Model;
    Assert.AreEqual(1, model.Id);
    Assert.AreEqual(&amp;quot;&lt;span style="color:#8b0000;"&gt;Mathematics&lt;/span&gt;&amp;quot;, model.Name);
}
&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;Curiosamente, detect&amp;eacute; un test &amp;ldquo;malo&amp;rdquo;. Yo hab&amp;iacute;a escrito en test AddSubject:&lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;Assert.IsTrue(subjects.Any(s =&amp;gt; s.Name == &amp;quot;&lt;span style="color:#8b0000;"&gt;Chemistry&lt;/span&gt;&amp;quot;));
Assert.AreEqual(4, subject.Id);&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;Pero el nuevo Id deber&amp;iacute;a dar 5 (mi lista usada en los tests tiene 4 temas predefinidos (&amp;ldquo;subjects&amp;rdquo;)):&lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;Assert.IsTrue(subjects.Any(s =&amp;gt; s.Name == &amp;quot;&lt;span style="color:#8b0000;"&gt;Chemistry&lt;/span&gt;&amp;quot;));
Assert.AreEqual(5, subject.Id);&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;Arregl&amp;eacute; el c&amp;oacute;digo y la acci&amp;oacute;n del controler, ejecut&amp;eacute; la aplicaci&amp;oacute;n web, y&amp;nbsp; voila! Todo funcion&amp;oacute;.&lt;/p&gt;
&lt;p&gt;Puntos principales:&lt;/p&gt;
&lt;p&gt;- Estoy usando un dominio en memoria. &lt;/p&gt;
&lt;p&gt;- Las vistas se ejecutan sobre las acciones YA probadas con tests&lt;/p&gt;
&lt;p&gt;No hay capa l&amp;oacute;gica de servicios ni persistencia, a&amp;uacute;n. Vean que no son necesarias al principio. Voy a agregar una &amp;ldquo;service layer&amp;rdquo; como gran refactor. Otros pr&amp;oacute;ximos pasos: agregar m&amp;aacute;s clases al dominio (libros en clase Book), escribir esa capa de servicio usando tests, &amp;ldquo;enchufarla&amp;rdquo; en los controladores. Y en alg&amp;uacute;n momento agregar persistencia.&lt;/p&gt;
&lt;p&gt;Pueden leer posts interesantes sobre TDD sin una base de datos (o agreg&amp;aacute;ndola despu&amp;eacute;s) escritos por &lt;a href="http://twitter.com/RonJeffries"&gt;@RonJeffries&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://xprogramming.com/articles/but-we-need-a-database-dont-we/"&gt;But We Need a Database &amp;hellip; Don&amp;rsquo;t We? | xProgramming.com&lt;/a&gt; 
  &lt;br /&gt;&lt;a href="http://xprogramming.com/articles/but-we-need-a-database-dont-we/"&gt;See? We Don&amp;rsquo;t Need a Database &amp;hellip; Yet | xProgramming.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Nos leemos!&lt;/p&gt;
&lt;p&gt;Angel &amp;ldquo;Java&amp;rdquo; Lopez 
  &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt; 
  &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1795259" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Desarrollo+de+Software/default.aspx">Desarrollo de Software</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/C+Sharp/default.aspx">C Sharp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Desarrollo+Agil/default.aspx">Desarrollo Agil</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/TDD/default.aspx">TDD</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/ASP.NET+MVC/default.aspx">ASP.NET MVC</category></item><item><title>Escribiendo una Aplicación usando TDD (Parte 4) Alta y Actualización</title><link>http://msmvps.com/blogs/lopez/archive/2011/06/02/writing_2D00_an_2D00_application_2D00_using_2D00_tdd_2D00_part_2D00_4_2D00_update_2D00_and_2D00_insert.aspx</link><pubDate>Thu, 02 Jun 2011 10:05:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1794129</guid><dc:creator>lopez</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1794129</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2011/06/02/writing_2D00_an_2D00_application_2D00_using_2D00_tdd_2D00_part_2D00_4_2D00_update_2D00_and_2D00_insert.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2011/03/31/writing_2D00_an_2D00_application_2D00_using_2D00_tdd_2D00_part_2D00_3_2D00_first_2D00_detail.aspx"&gt;Anterior Post&lt;/a&gt; &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2011/06/27/writing_2D00_an_2D00_application_2D00_using_2D00_tdd_2D00_part_2D00_5_2D00_adding_2D00_views.aspx"&gt;Siguiente Post&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;En el anterior post, implement&amp;eacute; la recuperaci&amp;oacute;n de los datos de un Tema de libros. No implement&amp;eacute; a&amp;uacute;n ninguna vista. Estoy escribiendo los tests, e implementando el c&amp;oacute;digo del controlador. Es hora de agregar un nuevo Tema (Subject), usando una acci&amp;oacute;n del controlador.&lt;/p&gt;
&lt;p&gt;Este fue mi primer test:&lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;[TestMethod]
&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; AddSubject()
{
    IList&amp;lt;Subject&amp;gt; subjects = GetSubjects();
    Subject subject = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Subject() { Name = &amp;quot;&lt;span style="color:#8b0000;"&gt;Chemistry&lt;/span&gt;&amp;quot; };
    SubjectController controller = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; SubjectController(subjects);
    ActionResult result = controller.Create(subject);
    Assert.IsNotNull(result);
    Assert.IsTrue(subjects.Any(s =&amp;gt; s.Name == &amp;quot;&lt;span style="color:#8b0000;"&gt;Chemistry&lt;/span&gt;&amp;quot;));
    Assert.AreNotEqual(0, subject.Id);
}
&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;GetSubjects() es un m&amp;eacute;todo ayudante que present&amp;eacute; en el anterior posts. Retorna una lista de temas para tests. Agregu&amp;eacute; una nueva acci&amp;oacute;n en la clase controladora, para que la soluci&amp;oacute;n compile:&lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; ActionResult Create(Subject subject)
{
    &lt;span style="color:#0000ff;"&gt;throw&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; NotImplementedException();
}
&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;Compil&amp;oacute;, y el test qued&amp;oacute; en rojo:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/apptdd0301.png" alt="" /&gt; &lt;/p&gt;
&lt;p&gt;Entonces, complet&amp;eacute; el m&amp;eacute;todo de acci&amp;oacute;n con el c&amp;oacute;digo m&amp;iacute;nimo para que pase el test:&lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; ActionResult Create(Subject subject)
{
   subject.Id = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.subjects.Max(s =&amp;gt; s.Id);
   subjects.Add(subject);
   &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; RedirectToAction(&amp;quot;&lt;span style="color:#8b0000;"&gt;Index&lt;/span&gt;&amp;quot;);
}
&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;Pero quiero redireccionar a la vista de detalle luego de haber dado de alta un item. Agrego el test:&lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;RedirectToRouteResult redirect = (RedirectToRouteResult)result;
Assert.IsTrue(&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.IsNullOrEmpty(redirect.RouteName));
Assert.IsTrue(redirect.RouteValues.ContainsKey(&amp;quot;&lt;span style="color:#8b0000;"&gt;id&lt;/span&gt;&amp;quot;));
Assert.AreEqual(subject.Id, redirect.RouteValues[&amp;quot;&lt;span style="color:#8b0000;"&gt;id&lt;/span&gt;&amp;quot;]);
Assert.IsTrue(redirect.RouteValues.ContainsKey(&amp;quot;&lt;span style="color:#8b0000;"&gt;action&lt;/span&gt;&amp;quot;));
Assert.AreEqual(&amp;quot;&lt;span style="color:#8b0000;"&gt;Details&lt;/span&gt;&amp;quot;, redirect.RouteValues[&amp;quot;&lt;span style="color:#8b0000;"&gt;action&lt;/span&gt;&amp;quot;]);
&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;Cambio el c&amp;oacute;digo de la acci&amp;oacute;n para que cumpla con el nuevo requerimiento:&lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; ActionResult Create(Subject subject)
{
    subject.Id = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.subjects.Max(s =&amp;gt; s.Id);
    subjects.Add(subject);
    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; RedirectToAction(&amp;quot;&lt;span style="color:#8b0000;"&gt;Details&lt;/span&gt;&amp;quot;, &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; { id = subject.Id });
}
&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;Ahora, el test en verde:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/apptdd0302.png" alt="" /&gt; &lt;/p&gt;
&lt;p&gt;Segu&amp;iacute; un camino similar para escribir el test de actualizaci&amp;oacute;n de un Tema existente. Esta es la versi&amp;oacute;n actual de ese test:&lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;[TestMethod]
&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; UpdateSubject()
{
    IList&amp;lt;Subject&amp;gt; subjects = GetSubjects();
    Subject literature = subjects.Where(s =&amp;gt; s.Name == &amp;quot;&lt;span style="color:#8b0000;"&gt;Literature&lt;/span&gt;&amp;quot;).FirstOrDefault();
    Subject subject = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Subject() { Name = &amp;quot;&lt;span style="color:#8b0000;"&gt;SciFi&lt;/span&gt;&amp;quot; };
    SubjectController controller = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; SubjectController(subjects);
    ActionResult result = controller.Update(literature.Id, subject);
    Assert.IsNotNull(result);
    Assert.IsInstanceOfType(result, &lt;span style="color:#0000ff;"&gt;typeof&lt;/span&gt;(RedirectToRouteResult));
    RedirectToRouteResult redirect = (RedirectToRouteResult)result;
    Assert.IsTrue(&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.IsNullOrEmpty(redirect.RouteName));
    Assert.IsTrue(redirect.RouteValues.ContainsKey(&amp;quot;&lt;span style="color:#8b0000;"&gt;id&lt;/span&gt;&amp;quot;));
    Assert.AreEqual(literature.Id, redirect.RouteValues[&amp;quot;&lt;span style="color:#8b0000;"&gt;id&lt;/span&gt;&amp;quot;]);
    Assert.IsTrue(redirect.RouteValues.ContainsKey(&amp;quot;&lt;span style="color:#8b0000;"&gt;action&lt;/span&gt;&amp;quot;));
    Assert.AreEqual(&amp;quot;&lt;span style="color:#8b0000;"&gt;Details&lt;/span&gt;&amp;quot;, redirect.RouteValues[&amp;quot;&lt;span style="color:#8b0000;"&gt;action&lt;/span&gt;&amp;quot;]);
    Assert.IsTrue(subjects.Any(s =&amp;gt; s.Name == &amp;quot;&lt;span style="color:#8b0000;"&gt;SciFi&lt;/span&gt;&amp;quot;));
    Assert.AreEqual(literature.Id, subjects.Where(s =&amp;gt; s.Name == &amp;quot;&lt;span style="color:#8b0000;"&gt;SciFi&lt;/span&gt;&amp;quot;).Single().Id);
}
&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;La acci&amp;oacute;n del controlador:&lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; ActionResult Update(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; id, Subject subject)
{
    Subject toupdate = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.subjects.Where(s =&amp;gt; s.Id == id).Single();
    toupdate.Name = subject.Name;
    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; RedirectToAction(&amp;quot;&lt;span style="color:#8b0000;"&gt;Details&lt;/span&gt;&amp;quot;, &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; { id = id });
}
&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;Todos los tests en verde:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/apptdd0303.png" alt="" /&gt; &lt;/p&gt;
&lt;p&gt;Algunas advertencias: los tests est&amp;aacute;n revisando dos salidas: los cambios en el dominio (por ahor auna simple lista) y los resultados de las acciones (un tema MVC). Deber&amp;iacute;a hacer refactor (seguramente en un futuro post) de la implementaci&amp;oacute;n del controlador, para separar las actualizaciones del dominio de los resultados de la navegaci&amp;oacute;n. Escrib&amp;iacute; el ejemplo de esta manera para mostrar c&amp;oacute;mo hacer refactor m&amp;aacute;s adelante para conseguir una mejor implementaci&amp;oacute;n. Mi idea es tener un servicio de manejo de temas, y escribir con tests. Luego usarlo desde el controlador. Deber&amp;iacute;a tambien tratar los casos de actualizaci&amp;oacute;n de un item inexistente o la creaci&amp;oacute;n de un item ya existente.&lt;/p&gt;
&lt;p&gt;Otra nota: no puse ninguna vista MVC todav&amp;iacute;a. Pero ahora ya tengo los tests como para agregarlas con confianza. Cuando las agregue, la conducta esperada del controlador ya estar&amp;aacute; probada.&lt;/p&gt;
&lt;p&gt;Nos leemos!&lt;/p&gt;
&lt;p&gt;Angel &amp;ldquo;Java&amp;rdquo; Lopez &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt; &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1794129" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Desarrollo+de+Software/default.aspx">Desarrollo de Software</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/C+Sharp/default.aspx">C Sharp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Desarrollo+Agil/default.aspx">Desarrollo Agil</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/TDD/default.aspx">TDD</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/ASP.NET+MVC/default.aspx">ASP.NET MVC</category></item><item><title>Escribiendo una Aplicación usando TDD (Parte 3) Primer Detalle</title><link>http://msmvps.com/blogs/lopez/archive/2011/03/31/writing_2D00_an_2D00_application_2D00_using_2D00_tdd_2D00_part_2D00_3_2D00_first_2D00_detail.aspx</link><pubDate>Thu, 31 Mar 2011 09:55:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1790946</guid><dc:creator>lopez</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1790946</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2011/03/31/writing_2D00_an_2D00_application_2D00_using_2D00_tdd_2D00_part_2D00_3_2D00_first_2D00_detail.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2011/03/01/writing_2D00_an_2D00_application_2D00_using_2D00_tdd_2D00_part_2D00_1_2D00_introduction.aspx"&gt;Primer post de la serie&lt;/a&gt; &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2011/06/02/writing_2D00_an_2D00_application_2D00_using_2D00_tdd_2D00_part_2D00_4_2D00_update_2D00_and_2D00_insert.aspx"&gt;Pr&amp;oacute;ximo post de la serie&lt;/a&gt; &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2011/03/25/writing_2D00_an_2D00_application_2D00_using_2D00_tdd_2D00_part_2D00_2_2D00_first_2D00_list.aspx"&gt;Anterior post de la serie&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Desde el anterior post, he aplicado las sugerencias que dejaron en comentarios &lt;a href="http://twitter.com/MartinSalias"&gt;@MartinSalias&lt;/a&gt; y &lt;a href="http://twitter.com/theHumanFlag"&gt;@theHumanFlag&lt;/a&gt;, gracias! (las dejaron en el &lt;a href="http://ajlopez.wordpress.com/2011/03/22/writing-an-application-using-tdd-part-2-first-list/"&gt;post en ingl&amp;eacute;s&lt;/a&gt;). Primero, renombr&amp;eacute; la clase Genre a Subject, usando las capacidades de refactoring de Visual Studio:&lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; Subject
{
    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; Name { &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt;; &lt;span style="color:#0000ff;"&gt;set&lt;/span&gt;; }
}
&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;Segundo, ahora el controlador recibe y procesa un&amp;nbsp; IEnumerable&amp;lt;Subject&amp;gt;:&lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; SubjectController : Controller
{
    &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; IEnumerable&amp;lt;Subject&amp;gt; subjects;
    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; SubjectController()
    {
    }
    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; SubjectController(IEnumerable&amp;lt;Subject&amp;gt; subjects)
    {
        &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.subjects = subjects;
    }
    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; ActionResult Index()
    {
        &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; View(subjects);
    }
}
&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;Hice los cambios con confianza, gracias a los tests.&lt;/p&gt;
&lt;p&gt;Ahora, en este nuevo paso, agregu&amp;eacute; una acci&amp;oacute;n: dado un Id, obtener el Subject. La propiedad Id agregada en Subjec:&lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; Subject
{
    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; Id { &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt;; &lt;span style="color:#0000ff;"&gt;set&lt;/span&gt;; }
    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; Name { &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt;; &lt;span style="color:#0000ff;"&gt;set&lt;/span&gt;; }
}
&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;Escrib&amp;iacute; el test:&lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;[TestMethod]
&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; GetSubjectForDetail()
{
    IEnumerable&amp;lt;Subject&amp;gt; subjects = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; List&amp;lt;Subject&amp;gt;()
    {
        &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Subject() { Id = 1, Name = &amp;quot;&lt;span style="color:#8b0000;"&gt;Mathematics&lt;/span&gt;&amp;quot; },
        &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Subject() { Id = 2, Name = &amp;quot;&lt;span style="color:#8b0000;"&gt;Physics&lt;/span&gt;&amp;quot; },
        &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Subject() { Id = 3, Name = &amp;quot;&lt;span style="color:#8b0000;"&gt;Biology&lt;/span&gt;&amp;quot; },
        &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Subject() { Id = 4, Name = &amp;quot;&lt;span style="color:#8b0000;"&gt;Literature&lt;/span&gt;&amp;quot; }
    };
    SubjectController controller = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; SubjectController(subjects);
    ActionResult result = controller.Details(1);
    Assert.IsNotNull(result);
    Assert.IsInstanceOfType(result, &lt;span style="color:#0000ff;"&gt;typeof&lt;/span&gt;(ViewResult));
    ViewResult viewResult = (ViewResult)result;
    Assert.IsInstanceOfType(viewResult.ViewData.Model, &lt;span style="color:#0000ff;"&gt;typeof&lt;/span&gt;(Subject));
    Subject model = (Subject)viewResult.ViewData.Model;
    Assert.AreEqual(1, model.Id);
    Assert.AreEqual(&amp;quot;&lt;span style="color:#8b0000;"&gt;Mathematics&lt;/span&gt;&amp;quot;, model.Name);
}
&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;El test no compila. Agregu&amp;eacute; la acci&amp;oacute;n en el controler:&lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; ActionResult Details(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; id)
{
    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; View();
}
&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;El test compila, pero da en rojo. Vamos por el verde:&lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; ActionResult Details(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; id)
{
    var model = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.subjects.Where(s =&amp;gt; s.Id == id).FirstOrDefault();
    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; View(model);
}
&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;En este punto, ten&amp;iacute;a dos tests, que daban una lista de Subjects al controlador. Hice refactoreo de los test para separar la creaci&amp;oacute;n de la lista. Extraje el m&amp;eacute;todo:&lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;static&lt;/span&gt; IEnumerable&amp;lt;Subject&amp;gt; GetSubjects()
{
    IEnumerable&amp;lt;Subject&amp;gt; subjects = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; List&amp;lt;Subject&amp;gt;()
    {
        &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Subject() { Id = 1, Name = &amp;quot;&lt;span style="color:#8b0000;"&gt;Mathematics&lt;/span&gt;&amp;quot; },
        &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Subject() { Id = 2, Name = &amp;quot;&lt;span style="color:#8b0000;"&gt;Physics&lt;/span&gt;&amp;quot; },
        &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Subject() { Id = 3, Name = &amp;quot;&lt;span style="color:#8b0000;"&gt;Biology&lt;/span&gt;&amp;quot; },
        &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Subject() { Id = 4, Name = &amp;quot;&lt;span style="color:#8b0000;"&gt;Literature&lt;/span&gt;&amp;quot; }
    };
    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; subjects;
}
&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;Ahora, el c&amp;oacute;digo del test es:&lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;[TestMethod]
&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; GetSubjectInDetail()
{
    IEnumerable&amp;lt;Subject&amp;gt; subjects = GetSubjects();
    SubjectController controller = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; SubjectController(subjects);
    ActionResult result = controller.Details(1);
    Assert.IsNotNull(result);
    Assert.IsInstanceOfType(result, &lt;span style="color:#0000ff;"&gt;typeof&lt;/span&gt;(ViewResult));
    ViewResult viewResult = (ViewResult)result;
    Assert.IsInstanceOfType(viewResult.ViewData.Model, &lt;span style="color:#0000ff;"&gt;typeof&lt;/span&gt;(Subject));
    Subject model = (Subject)viewResult.ViewData.Model;
    Assert.AreEqual(1, model.Id);
    Assert.AreEqual(&amp;quot;&lt;span style="color:#8b0000;"&gt;Mathematics&lt;/span&gt;&amp;quot;, model.Name);
}
&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;Todo en verde!&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/apptdd0201.png" alt="" /&gt; &lt;/p&gt;
&lt;p&gt;Como siempre, el c&amp;oacute;digo est&amp;aacute; en mi &lt;a href="http://code.google.com/p/ajcodekatas/"&gt;AjCodeKatas Google Project&lt;/a&gt;, esta vez en&amp;nbsp; trunk/AppTdd/Step02)&lt;/p&gt;
&lt;p&gt;Pr&amp;oacute;ximos pasos: m&amp;aacute;s acciones, integrar alguna vista. &lt;/p&gt;
&lt;p&gt;Nos leemos!&lt;/p&gt;
&lt;p&gt;Angel &amp;ldquo;Java&amp;rdquo; Lopez &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt; &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1790946" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/C+Sharp/default.aspx">C Sharp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Desarrollo+Agil/default.aspx">Desarrollo Agil</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/TDD/default.aspx">TDD</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/ASP.NET+MVC/default.aspx">ASP.NET MVC</category></item><item><title>Escribiendo una Aplicación usando TDD (Parte 2) Primera lista</title><link>http://msmvps.com/blogs/lopez/archive/2011/03/25/writing_2D00_an_2D00_application_2D00_using_2D00_tdd_2D00_part_2D00_2_2D00_first_2D00_list.aspx</link><pubDate>Fri, 25 Mar 2011 14:48:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1790545</guid><dc:creator>lopez</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1790545</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2011/03/25/writing_2D00_an_2D00_application_2D00_using_2D00_tdd_2D00_part_2D00_2_2D00_first_2D00_list.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2011/03/31/writing_2D00_an_2D00_application_2D00_using_2D00_tdd_2D00_part_2D00_3_2D00_first_2D00_detail.aspx"&gt;Siguiente post en esta serie &lt;/a&gt;&lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2011/03/01/writing_2D00_an_2D00_application_2D00_using_2D00_tdd_2D00_part_2D00_1_2D00_introduction.aspx"&gt;Anterior post en esta serie&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Gracias a un comentario de &lt;a href="http://twitter.com/MartinSalias"&gt;@MartinSalias&lt;/a&gt;, en mi post anterior, eleg&amp;iacute; para desarrollar este ejemplo un dominio simple: mi biblioteca personal, mis libros. En esta primera iteraci&amp;oacute;n de c&amp;oacute;digo, quiero listar los temas de los libros: F&amp;iacute;sica, Matem&amp;aacute;ticas, Biolog&amp;iacute;a, Literatura&amp;hellip; (similar a los g&amp;eacute;nereos del ejemplo &lt;a href="http://mvcmusicstore.codeplex.com/"&gt;MvcMusicStore&lt;/a&gt; de &lt;a href="http://twitter.com/jongalloway"&gt;@jongalloway&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Primero, cre&amp;eacute; una soluci&amp;oacute;n ASP.NET MVC 2 (estoy usando Visual Studio 2008) (el c&amp;oacute;digo de este post, como siempre, queda en mi &lt;a href="http://code.google.com/p/ajcodekatas/"&gt;AjCodeKatas Google Project&lt;/a&gt;, en el directorio trunk/AppTdd/Step01)&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/apptdd0101.png" alt="" /&gt; &lt;/p&gt;
&lt;p&gt;Luego, agregu&amp;eacute; un proyecto de test:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/apptdd0102.png" alt="" /&gt; &lt;/p&gt;
&lt;p&gt;A este proyecto le agregu&amp;eacute; referencias a System.Web.Mvc and MyLibrary.Web.&lt;/p&gt;
&lt;p&gt;Agregu&amp;eacute; un test:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/apptdd0103.png" alt="" /&gt; &lt;/p&gt;
&lt;p&gt;Limpi&amp;eacute; el c&amp;oacute;digo de la clase generada por el wizard, removiendo c&amp;oacute;digo no usado. Qued&amp;oacute;:&lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;namespace&lt;/span&gt; MyLibrary.Web.Tests.Controllers
{
    &lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System;
    &lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System.Text;
    &lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System.Collections.Generic;
    &lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System.Linq;
    &lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; Microsoft.VisualStudio.TestTools.UnitTesting;
    [TestClass]
    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; GenreControllerTests
    {
    }
}
&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;Ahora, agregu&amp;eacute; mi primer test:&lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;        [TestMethod]
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; GetGenres()
        {
            IList&amp;lt;Genre&amp;gt; genres = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; List&amp;lt;Genre&amp;gt;()
            {
                &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Genre() { Name = &amp;quot;&lt;span style="color:#8b0000;"&gt;Mathematics&lt;/span&gt;&amp;quot; },
                &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Genre() { Name = &amp;quot;&lt;span style="color:#8b0000;"&gt;Physics&lt;/span&gt;&amp;quot; },
                &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Genre() { Name = &amp;quot;&lt;span style="color:#8b0000;"&gt;Biology&lt;/span&gt;&amp;quot; },
                &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Genre() { Name = &amp;quot;&lt;span style="color:#8b0000;"&gt;Literature&lt;/span&gt;&amp;quot; }
            };
            GenreController controller = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; GenreController(genres);
            ActionResult result = controller.Index();
            Assert.IsNotNull(result);
            Assert.IsInstanceOfType(result, &lt;span style="color:#0000ff;"&gt;typeof&lt;/span&gt;(ViewResult));
            ViewResult viewResult = (ViewResult)result;
            Assert.IsInstanceOfType(viewResult.ViewData.Model, &lt;span style="color:#0000ff;"&gt;typeof&lt;/span&gt;(IList&amp;lt;Genre&amp;gt;));
            Assert.AreSame(genres, viewResult.ViewData.Model);
        }
		&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;La idea del test: crear el controlador, alimentarlo de una lista de temas, y luego invocar su acci&amp;oacute;n Index. Hecho eso, controlar el resultado. A esta altura, el c&amp;oacute;digo no compilaba: el controlador no exist&amp;iacute;a, no hab&amp;iacute;a clase Genre. As&amp;iacute; que escrib&amp;iacute; esas clases. La clase Genre, en el directorio Model del proyecto MyLibrary.Web:&lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; Genre
    {
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; Name { &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt;; &lt;span style="color:#0000ff;"&gt;set&lt;/span&gt;; }
    }
&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;Un controlador simple GenreController (agregado con click derecho sobre el directorio Controllers):&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/apptdd0104.png" alt="" /&gt; &lt;/p&gt;
&lt;p&gt;El wizard produjo este c&amp;oacute;digo:&lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; GenreController : Controller
    {
        &lt;span style="color:#008000;"&gt;//&lt;/span&gt;
        &lt;span style="color:#008000;"&gt;// GET: /Genre/&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; ActionResult Index()
        {
            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; View();
        }
    }
&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;Lo modifiqu&amp;eacute; para que tenga el constructor que necesito en el test:&lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; GenreController : Controller
    {
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; GenreController()
        {
        }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; GenreController(IList&amp;lt;Genre&amp;gt; genres)
        {
        }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; ActionResult Index()
        {
            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; View();
        }
    }
	&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;Noten que mi intenci&amp;oacute;n es compilar el test, no que fuencione: la lista de temas no es usada por esta primer implementaci&amp;oacute;n de controlador. Con todos estos cambios, pude compilar la soluci&amp;oacute;n y ejecutar el test:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/apptdd0105.png" alt="" /&gt; &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;El resultado:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/apptdd0106.png" alt="" /&gt; &lt;/p&gt;
&lt;p&gt;El problema:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/apptdd0107.png" alt="" /&gt; &lt;/p&gt;
&lt;p&gt;Como esperaba. Esto es parte del ciclo TDD: compilar, rojo, y ahora, hay que ir por el verde.&lt;/p&gt;
&lt;p&gt;Cambi&amp;eacute; el controlador (su interfaz ya estaba completa):&lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; GenreController : Controller
    {
        &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; IList&amp;lt;Genre&amp;gt; genres;
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; GenreController()
        {
        }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; GenreController(IList&amp;lt;Genre&amp;gt; genres)
        {
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.genres = genres;
        }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; ActionResult Index()
        {
            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; View(genres);
        }
    }
&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;Y ahora, el resultado es:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/apptdd0108.png" alt="" /&gt; &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Triunfo de la mente sobre la materia! ;-)&lt;/p&gt;
&lt;p&gt;Ahora, es tiempo de refactoring. Bien, no tengo mucho para hacer ahora (me llega un comentario en &lt;a href="http://ajlopez.wordpress.com/2011/03/22/writing-an-application-using-tdd-part-2-first-list/"&gt;mi post en ingl&amp;eacute;s&lt;/a&gt; de &lt;a href="http://twitter.com/MartinSalias"&gt;@MartinSalias&lt;/a&gt;, sugiriendo cambios en la nomenclatura, bien, quedar&amp;aacute; para el pr&amp;oacute;ximo paso). Podr&amp;iacute;a mejorar alguna variable, nombre. La principal pieza faltante: la vista. Nota: el controlador no est&amp;aacute; preparado, a&amp;uacute;n, para ser consumido por una vista. No hay quien le provea los temas en ejecuci&amp;oacute;n. En el test, us&amp;eacute; un constructor que se los provee, pero ASP.NET MVC crear&amp;iacute;a la instancia del controlador usando el constructor sin par&amp;aacute;metros.&lt;/p&gt;
&lt;p&gt;Pr&amp;oacute;ximos pasos: mejorar el controlador para usar una vista, algunas acciones CRUD con tests, y vistas.&lt;/p&gt;
&lt;p&gt;Podr&amp;iacute;an preguntar: &amp;iquest;d&amp;oacute;nde est&amp;aacute; el repositorio de los temas? &amp;iquest;d&amp;oacute;nde est&amp;aacute;n los libros? &amp;iquest;y la base de datos? &amp;iquest;y la capa de servicios (service layer)? &amp;iquest;separaci&amp;oacute;n del dominio? Ok, son todas preguntas v&amp;aacute;lidas y temas a tratar. Pero mi idea es mostrar, de forma incremental, con TDD, c&amp;oacute;mo podemos ir agregando todo eso a medida que aparezcan m&amp;aacute;s requerimientos y especificaciones. Quiero que cada cosa que se agregue provenga del proceso de escribir test (ya sea de la especificaci&amp;oacute;n del test, o de la etapa de refactoring). Como escrib&amp;iacute; en &lt;a href="http://msmvps.com/blogs/lopez/archive/2011/03/01/writing_2D00_an_2D00_application_2D00_using_2D00_tdd_2D00_part_2D00_1_2D00_introduction.aspx"&gt;mi anterior post&lt;/a&gt;, esta es una clase de aproximaci&amp;oacute;n arriba-abajo (top-down). En este caso, el dominio es simple, as&amp;iacute; que comienzo desde el tope de la presentaci&amp;oacute;n. Luego de este ejemplo simple, a desarrollar en varios post, cambiar&amp;eacute; a un dominio menos simple. En ese caso, comenzar&amp;eacute; por construir por tests al propio dominio, en lugar de la presentaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;Nos leemos!&lt;/p&gt;
&lt;p&gt;Angel &amp;ldquo;Java&amp;rdquo; Lopez &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt; &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1790545" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Desarrollo+de+Software/default.aspx">Desarrollo de Software</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/C+Sharp/default.aspx">C Sharp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Desarrollo+Agil/default.aspx">Desarrollo Agil</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/TDD/default.aspx">TDD</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/ASP.NET+MVC/default.aspx">ASP.NET MVC</category></item></channel></rss>