Home RSS 2.0 ATOM 1.0  CDF  
 
CodeSegment - Carlos Segura Sanz (blog)
 
Page 1 of 10 in the SharePoint-es category Next Page

Muchos de los desarrolladores de SharePoint, terminan optando por desplegar sus aplicaciones en el GAC, para evitar problemas de seguridad. Esta no es la manera más correcta y cada vez más administradores de sistemas, exigen que las soluciones se desplieguen en los directorios de aplicación.

Los ensamblados que se ejecutan desde el GAC, se ejecutan bajo total confianza (Full Trust) y están disponibles para todos los servidores virtuales y todas las aplicaciones, lo cual termina siendo menos seguro si desconocemos la procedencia del ensamblado, cosa que ocurre con frecuencia.

La seguridad de acceso al código nos permite restringir los tipos de recursos a los cuales puede acceder el código así como las operaciones privilegiadas que este puede realizar.

ASP.Net incluye cinco niveles de seguridad Full, High, Medium, Low, and Minimal. (Completo, alto, medio, bajo y mínimo) estos niveles de seguridad los establecemos en el web.config de nuestra aplicación web, bajo la etiqueta de SecurityPolicy. (Las declaraciones de dichas políticas pueden verse en C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG)

SharePoint, añade dos políticas de seguridad personalizadas, WSS_Medium y WSS_Minimal, (minima confianza, confianza media) cuyos archivos de política pueden verse en (C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\CONFIG)

En el caso de WSS y MOSS, nuestro web.config comienza en WSS_Minimal y conforme vamos desplegando soluciones que incluyen políticas de acceso personalizadas este archivo pasa a ser WSS_Custom.

Básicamente las diferencias establecidas entre los modelos WSS_Minimal y WSS_Medium es que WSS_Minimal, no concede los permisos (DnsPermission, EnvironmentPermission, FileIOPermission, IsolatedStorageFilePermission, PrintingPermission, SharePointPermission, SmtpPermission, SqlClientPermission y UIPermission)

Es decir, que con el modelo WSS_Minimal, no podemos realizar ninguna operación de archivo, (leer/escribir), no podemos acceder a las variables de entrono o acceder a datos … incluido el usar el modelo de objetos de SharePoint. Vamos, en una palabra otorgamos la mínima confianza.

Recursos y permisos asociados

Secure Resource Requires Permission
Data access SqlClientPermission
OleDbPermission
OraclePermission
Directory services DirectoryServicesPermission
DNS databases DnsPermission
Event log EventLogPermission
Environment variables EnvironmentPermission
File system FileIOPermission
Isolated storage IsolatedStoragePermission
Message queues MessageQueuePermission
Performance counters PerformanceCounterPermission
Printers PrinterPermission
Registry RegistryPermission
Sockets SocketPermission
Web services (and other HTTP Internet resources) WebPermission
SharePoint Object Model SharePointPermission

De modo que en nuestros archivos para el despliegue de soluciones de SharePoint debemos incluir muestra política de seguridad definiendo nuestro CAS.

Evidentemente para muchos lo más fácil es indicar en el ensamblado DeploymentTarget="GlobalAssemblyCache" con lo cual nuestro ensamblado ira a parar al GAC obteniendo confianza total.

Para hacer un despliegue correcto y seguro, lo que debemos hacer es desplegar nuestro ensamblado en el directorio bin de la aplicación web, DeploymentTarget="WebApplication" y crear nuestra política de seguridad de código.

En el mismo archivo de solución, podemos indicar nuestra CAS :

<CodeAccessSecurity>
    <PolicyItem>
      <PermissionSet class="NamedPermissionSet" 
                     version="1" 
	             Description="Permisos para nuestro ensamblado">
        <IPermission class="AspNetHostingPermission" 
                     version="1" 
	             Level="Minimal" />
        <IPermission class="SecurityPermission" 
                     version="1" 
	  	     Flags="Execution" />
        <IPermission class="Microsoft.SharePoint.Security.SharePointPermission,
	  Microsoft.SharePoint.Security, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
                     version="1" 
                     ObjectModel="True" 
                     Impersonate="True"  
                     Unrestricted="True" />
        <IPermission class="System.Security.Permissions.SecurityPermission, 
	  mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" 
                     version="1" 
                     Flags="ControlThread, Execution" />
    </PermissionSet>
    <Assemblies>
       <Assembly Name="IdeSeg.SharePoint.WebParts.dll"  />
    </Assemblies>
  </PolicyItem>
</CodeAccessSecurity>

Donde establecemos la política de seguridad de acceso, estableciendo nuestro conjunto personalizado de permisos. Después debemos hacer el despliegue con STSADM -deploysolution solution -allowCasPolicies

 

Wednesday, July 23, 2008 6:08:19 PM (Hora de verano romance, UTC+02:00)   #    Comments [0]   SharePoint-es  | 

Después de pasar algunas horas tratando de resolver un problema con las búsquedas incrementales en una instalación de MOSS, os recuerdo los hotfixes que han ido saliendo tras el SP1 el kb948945 ha solucionado el mio ...


Thursday, July 10, 2008 10:09:13 PM (Hora de verano romance, UTC+02:00)   #    Comments [0]   SharePoint-es  | 

En todas las instalaciones hay un punto crítico, esa pregunta que no tenemos muy clara  y que en ocasiones va acompañada de un texto recomendando una de las opciones, por si no sabemos muy bien qué es lo que estamos haciendo. MOSS no es una excepción.

La pregunta en cuestión llega cuando tenemos que decidir sobre la seguridad, la instalación de MOSS nos da a elegir entre sí usaremos NTLM ó Kerberos.

Como todos sabemos y Microsoft dice NTLM funciona para casi todo. De modo que suele ser la opción preferida de todos.  No hay que configurar nada y funciona. (http://support.microsoft.com/kb/832769)

Kerberos por el contrario es un sistema de autentificación un poco más complejo, pero  también más seguro y más rápido (motivos por los cuales ya de por sí, debería ser la opción predilecta de todos)

Kerberos, es más rápido por que guarda en una cache (vales) la información del cliente después de que este se ha autentificado en el sistema, de modo que no tiene que estar comprobando las credenciales una y otra vez.

Otra de las características importantes de Kerberos es la Delegación, La delegación nos permite pasar las credenciales del cliente desde nuestro servidor front-end (SharePoint)  a nuestros servidores back-end (SQL Server etc..).

Cuando usamos NTLM, y deseamos acceder a recursos que están fuera de nuestro alcance, podemos suplantar al cliente (impersonate)  y usar la cuenta de suplantación para realizar las tareas necesarias.

¿Pero qué ocurre cuando tratamos de usar recursos que no están en la misma máquina que nuestro servidor web?, entonces la suplantación no es suficiente. Y se produce el efecto llamado Double-Hop (http://support.microsoft.com/default.aspx?scid=kb;en-us;329986)

Imaginemos que hemos realizado una solución para SharePoint que usa un servicio web o una conexión a un servidor SQL que se encuentra en una máquina distinta, y deseamos acceder usando la seguridad integrada (Integrated Security=SSPI) .

Al realizar la conexión nuestro servidor web debe ponerse en contacto con nuestro servidor SQL y este no es capaz de autentificar al usuario.

De modo que recibiremos un mensaje como:

Login failed for user 'NT AUTHORITY\ANONYMOUS LOGON'.

Como mencionaba anteriormente, esto es debido a que la suplantación no es válida, necesitamos algo más; Delegación.

Y esa delegación aunque cueste un poquito más configurarla es la que nos ofrece Kerberos.

Este escenario se produce en multitud de instalaciones de MOSS en donde usamos servicios de Excel, para recuperar datos de los servicios de análisis de SQL.

Thursday, February 21, 2008 4:04:04 PM (Hora estándar romance, UTC+01:00)   #    Comments [5]   SharePoint-es  | 

Alguien me ha recordado que empecé a escribir sobre el tema de las pruebas unitarias y finalmente no termine… o por lo menos no conté algunas de las prácticas que uso… cierto.

Parte 1 - Parte 2

Básicamente la técnica que uso habitualmente consiste en aprovisionar un sitio de forma automática. Y ¿Cómo se aprovisiona un sitio automáticamente?, pues de la manera más sencilla posible. Usando Plantillas.

Provisión - Escenario de Pruebas

De modo que tengo distintas plantillas pre cargadas con listas, bibliotecas de documentos, páginas etc… algunas incluyendo contenido, archivos, elementos de las listas y un montón de cosas.

Es sencillísimo crear estos escenarios y pueden ser simples, incluyendo uno ó unos pocos elementos ó complejos incluyendo una jerarquía de de sitios, en cuyo caso crearemos una plantilla por cada sitio para más tarde reconstruir una jerarquía de sitios determinada.

Después usamos un ayudante en nuestras pruebas para aprovisionar nuestros sitios, un ejemplo de un aprovisionador de sitios  básico sería algo como esto, he recortado algunas cosas ...

public class SPProvisioningHelper
{
private const string DefaultWebName = "TestSite";
private readonly Dictionary<string, SPWeb> _webs;

private SPSite _site;
private string _urlTestSite;

public SPProvisioningHelper()
{
_webs = new Dictionary<string, SPWeb>();
UrlTestSite = "http://enjendro/unittests/";
}

// Url del sitio de pruebas public string UrlTestSite
{
get { return _urlTestSite; }
set { _urlTestSite = value; }
}

// Coleccion de sitios sobre la que estamos trabajando public SPSite Site
{
get { return _site; }
}

// Una web determianda public SPWeb GetWeb(string name)
{
return _webs[name];
}

// Provisiona una web vacia colgada de parentUrl // Pruebas rápidas y de creación de elementos public void WebProvisioning(string parentUrl)
{
_webs.Add(DefaultWebName, CreateWeb(DefaultWebName, parentUrl, string.Empty));
}

// Crea una web public void WebProvisioning(string name, string parentUrl)
{
_webs.Add(name, CreateWeb(name, parentUrl, string.Empty));
}

// Crea una web basada en una plantilla public void WebProvisioning(string name, string parentUrl, string template)
{
_webs.Add(name, CreateWeb(name, parentUrl, template));
}

// Crea las webs (hace el trabajo duro) private SPWeb CreateWeb(string title, string parentUrl, string template)
{
Trace.WriteLine(string.Format("Creating test web {0} at {1}", title, parentUrl));

_site = new SPSite(UrlTestSite + parentUrl);
SPWeb web = _site.OpenWeb();
SPWeb newWeb;

// Stop if (web == null)
{
throw new SPException(string.Format("Can´t open SharePoint Site in: {0}", _site.Url));
}

// Si existe lo borramos if (web.Webs[title].Exists)
{
RecursiveDeleteWebs(web.Webs[title]);
web.Webs[title].Delete();
}

// Web vacio if (template.Equals(string.Empty))
{
newWeb = web.Webs.Add(title);
}
else { // web basado en plantilla personalizada try
{
SPWebTemplateCollection webTemplateCollection;
webTemplateCollection = _site.GetCustomWebTemplates((uint) web.Locale.LCID);

SPWebTemplate webTemplate = webTemplateCollection[template];

newWeb = web.Webs.Add(title,
title,
string.Empty,
(uint) web.Locale.LCID,
webTemplate,
true,
false);
}
// web basado en plantilla no personalizada catch (ArgumentException)
{
newWeb = web.Webs.Add(title,
title,
string.Empty,
(uint) web.Locale.LCID,
template,
true,
false);
}
}

Trace.WriteLine(string.Format("Created web {0} at {1}", newWeb.Title, newWeb.Url));

return newWeb;
}

// Limpieza public void Clean()
{
DeleteWebs();
// Disposes } // Elimina las webs private void DeleteWebs()
{
foreach (SPWeb web in _webs.Values)
{
RecursiveDeleteWebs(web);
}
}

// Elimina todo recursivamente private void RecursiveDeleteWebs(SPWeb parentWeb)
{
// ... } }

Pruebas

Después en nuestras pruebas podemos inicializar los distintos escenarios, veamos un ejemplo usando el aprovisionador anterior

[TestFixture]
public class Tests
{
// El ayudante private SPProvisioningHelper provisioningHelper;

[TestFixtureSetUp]
public void Setup()
{
// Incializamos el ayudante provisioningHelper = new SPProvisioningHelper();

// Ejemplos // Aprovisionamos p1 desde una plantilla nuestra provisioningHelper.WebProvisioning("p1", "P1", "Plantilla1.stp");

// jerarquia provisioningHelper.WebProvisioning("p1", string.Empty);

// p1/p1a -> sitio de grupo provisioningHelper.WebProvisioning("p1a", "p1", "STS");

// p1/p1b -> un blog provisioningHelper.WebProvisioning("p1b", "p1", "Blog");

// p1/p1a/p1a1 -> un wiki provisioningHelper.WebProvisioning("p1a1", "p1/p1a", "Wiki");

// p1/p1a/p1a1/p1a11 -> sitio en blanco provisioningHelper.WebProvisioning("p1a11", "p1/p1a/p1a1");

}

// Una prueba simple [Test] public void GetCurrentUserName()
{
string expectedUser = WindowsIdentity.GetCurrent().Name;

SPUser user = provisioningHelper.GetWeb("p1").CurrentUser;

string userName = user.LoginName;

Trace.WriteLine(string.Format("Expected: {0} User: {1}", expectedUser, userName));
Assert.IsTrue(expectedUser.Equals(userName,StringComparison.OrdinalIgnoreCase));
}

// Limpieza [TestFixtureTearDown] public void TearDown()
{
provisioningHelper.Clean();
}
}

Esto es básicamente, desde luego como ocurre con todos los sistemas que deben ser aprovisionados, estos llevan su tiempo, en cualquier caso tampoco me parece tanto y además hay unos estupendos quad core relativamente baratos así que no es escusa para no tener una máquina de pruebas.

Wednesday, December 12, 2007 10:44:44 PM (Hora estándar romance, UTC+01:00)   #    Comments [0]   NET Development | SharePoint-es  | 

El martes 23 de Octubre, se celebra en Madrid la tercera conferencia de usuarios de SharePoint.

Si queréis asistir, debéis registraros con anterioridad, es imprescindible.

Por la mañana habrá diversas ponencias comentando casos prácticos de implantación y por la tarde sesiones técnicas. La agenda completa se puede consultar en este ENLACE.

10:00  Bienvenida y Situación General de SharePoint
10:20  Experiencia Criteria Caixa Corp
10:50  Experiencia Ancert - Agencia Notarial de Certificación
11:20  Experiencia Ministerio de la Presidencia
11:50  Descanso y café
12:20  Experiencia Caja Mediterráneo
12:50  Microsoft Office Sharepoint en Intenet - Web 2.0 - Silver Light
13:20  Búsqueda Empresarial - Search
13:40  Futuro de SharePoint
14:00  Almuerzo


Para más información llamar al 902322344 o un email a eventos.microsoft@sitel.es

Y podéis registraros AQUÍ.

 

Thursday, October 25, 2007 6:35:11 PM (Hora de verano romance, UTC+02:00)   #    Comments [0]   SharePoint-es  | 

Y el séptimo día, descansó

¿Pero? ¿Y si hubiera tenido que seguir un día tras otro y una semana tras otra? Más o menos lo que nos pasa a los desarrolladores, el trabajo nunca termina, con una línea completas un método, con un método una clase, con una clase un caso de uso un espacio de nombres, una biblioteca… siempre habrá detrás otra nueva clase, otra nueva biblioteca y así sin parar.

Un día tras otro…  codificando, depurando, compilando, probando, no pongo meando porque a veces creo que me lo puedo hacer encima por no despegar los dedos del teclado …

Y a todo esto, cientos y cientos de tecnologías a nuestro alrededor que cambian constantemente, ¿y si a Dios le hubiesen cambiado las especificaciones una y otra vez?, y ¿si cada día hubiera tenido una nueva tecnología a su alcance?

Sinceramente, el mundo estaría por hacer. Sólo con el tiempo que lleva aprender, probar, crear un manual de buenas prácticas y realizar un framework adaptable y extensible y bla bla bla, para poder empezar a trabajar… estaría todavía diseñando a Adán.

Y eso gracias a que no dejo que Adán  diera las especificaciones de Eva, porque todavía estaríamos esperando… (Lo digo sin ánimo de ser machista), porque estaríamos  todavía en alguna iteración de la metodología divina, comprobando si el modelo cumple con las especificaciones del cliente.

En fin, si las cosas fueron así de rápidas supongo que serian por que no había, “cliente” y ¿si no había cliente?, ¿si no había especificaciones?, siempre me quedaré con la duda si se pudo hacer  en 5 ó incluso en 4 días y se demoró el asunto. Digo yo, que siendo Dios, podía haberlo hecho todo en UNO, Mundo y Ploffff, toma MUNDO.

De modo que no me queda más que pensar que uso algún tipo de metodología para acometer el trabajo. ¿Cuál?, ¿Cómo hacer un mundo en 6 días y descansar el 7º? ó tal vez usó ¿Cómo hacer el mundo en 4 días y descansar 3?, desde luego que si uso esta no consiguió su objetivo, a pesar de la metodología.

Creo que nos quedaremos sin saberlo…

Volviendo al asunto, que en absoluto es la metodología, si no la gran cantidad de tecnologías de las que disponemos, y la gran cantidad de las que dispondremos en breve.  Haciendo un pequeño resumen de las que necesitamos para desarrollar, pongamos por ejemplo SharePoint… un lenguaje .Net(C# ó VB.Net), Html, ASP.Net, XML, XSLT, JavaScript, Windows Workflow Foundation, InfoPath, TSQL, un SDK gordito y sin ejemplos, con más de 120Mb, 98 NameSpaces y 1.256 clases…

¿Sabéis una cosa? Yo quiero, que llegue el 7º Día.

Tuesday, September 25, 2007 8:03:13 PM (Hora de verano romance, UTC+02:00)   #    Comments [2]   Misc | NET Development | SharePoint-es  | 

Jhon Holliday (tambien MVP de SharePoint) lidera un proyecto llamado CAML.Net, que es una manera muy inteligente de integrar las consultas CAML en cualquier lenguaje .Net, con CAML.Net podemos mantener la estructura de las consultas de una manera intuitiva y natural, permitiéndonos construir componentes reusables.
 
Además podemos realizar data-bindings con los resultados devueltos por las consultas, de manera brillante. Además está trabajando en un editor visual que tiene un aspecto excelente.

Podéis leer más sobre CAML.Net en:

Working with CAML.Net - Part 1
Working with CAML.Net - Part 2 (Introducing the CAML)

y el proyecto está en CodePlex http://codeplex.com/camldotnet

Yo he seguido jugando con YACAMLQT mi programita y he decidido adaptarlo para generar también :-) CAML.Net.



 YACAMLQT.zip (15,07 KB)

Update: Thanks to Cameron to report the Gq/Gt bug.

Friday, September 07, 2007 2:08:19 PM (Hora de verano romance, UTC+02:00)   #    Comments [0]   SharePoint-es  | 

Como comentaba hace unos días, realizar pruebas unitarias usando mocks, no se siempre la mejor solución, personalmente, creo que no se debe abusar de ellos y usarlos para todo.

A continuación os cuento, como realizo mis pruebas unitarias cuando programo para SharePoint, seguramente no sean lo más idóneo del mundo, pero como dije en su día, no considero esto una ciencia sino más bien, un arte en donde cada uno utiliza aquello con lo que obtiene los mejores resultados, en cuanto a calidad. Siempre mantengo en mente el principio de que no deben llevar más trabajo que la realización del código.

El SDK de SharePoint, como comenté con anterioridad, es un framework con lo cual debemos dar por hecho algunas cosas, tenemos que tener claro que Microsoft, tomo ciertas decisiones en su diseño que por ende, nosotros no podemos cambiar.

SharePoint consta de un complejo modelo de objetos, en tres capas. De modo que cada vez que manipulamos estos, de forma transparente vamos cambiando la base de datos donde estos son persistidos. Esta cuestión es importante ya que es como si trabajásemos contra una base de datos y todos los que han realizado pruebas unitarias con bases de datos, saben la complejidad añadida que esto conlleva. Al margen de la discusión ya conocida sobre si las pruebas unitarias deben o no deben usar la base de datos como apunto Rodrigo.

Yo soy de la opinión de que mientras se pueda (por que se conoce) que base de datos se va a usar y podemos recrear un modelo de los datos sin un gran esfuerzo, es la mejor opción.

En SharePoint, aplico el mismo principio. Por diseño, la base de datos esta de manera subyacente así que la mejor manera de probar las cosas es usándola.

Mis pruebas con las Webparts

Las Webparts son un elemento dentro de SharePoint que nos permite interactuar con el usuario, a través del interface de usuario. En esta nueva versión como sabéis son los nativos de ASP.Net.

Como tales elementos, debemos confiar en que el comportamiento que tienen es el esperado, y me centro en realizar pruebas de la lógica subyacente, aquello que se encargará de producir los resultados en función de las entradas que reciba.

Veamos un simple ejemplo con un webpart que muestra el número de elementos que cumplen una condición en una lista.

private string _list = string.Empty;
private string _message = string.Empty;
private string _query = string.Empty;

#region WEBPART PROPERTIES
[Personalizable(PersonalizationScope.Shared),
 WebBrowsable,
 Category("Settings"),
 WebDisplayName("List Name")]
public string List
{
...
}

[Personalizable(PersonalizationScope.Shared),
 WebBrowsable,
 Category("Settings"),
 WebDisplayName("CAML Query")]
public string Query
{
...
}

[Personalizable(PersonalizationScope.Shared),
 WebBrowsable,
 Category("Settings"),
 WebDisplayName("Mesaage")]
public string Message
{
...
}
#endregion

protected override void Render(HtmlTextWriter output)
{            
    try
    {
        SPWeb web = SPControl.GetContextWeb(Context);
        SPList list = web.Lists[List];
        SPQuery query = new SPQuery();
        query.Query = Query;
        SPListItemCollection items = list.GetItems(query);
        output.Write("<div>{0}<b>{1}</b></div>", Message, CountListItems(web, List, Query));
    }
    catch (Exception ex)
    {
        output.Write(String.Format("<div>{0}: {1}</div>", ex.GetType(), ex.Message));
    }
}

Bien, aquí algunas buenas prácticas que suelo recomendar. Siempre que podamos debemos independizar nuestra lógica del componente, esto lo podemos hacer bien separando nuestro código en nuevos métodos:

protected override void Render(HtmlTextWriter output)
{
    SPWeb web = SPControl.GetContextWeb(Context);
    try
    {
        output.Write("<div>{0}<b>{1}</b></div>", Message, CountListItems(web, List, Query));
    }
    catch (Exception ex)
    {
        output.Write(String.Format("<div>{0}: {1}</div>", ex.GetType(), ex.Message));
    }
}

private int CountListItems(SPWeb web, string listName, string queryFiler)
{
    SPList list = web.Lists[listName];
    SPQuery query = new SPQuery();
    query.Query = queryFiler;
    SPListItemCollection items = list.GetItems(query);

    return items.Count;
}

O lo que es mejor, aplicando los principios de delegación o composición para extraer las responsabilidades y la lógica a una nueva clase.

protected override void Render(HtmlTextWriter output)
{
    SPWeb web = SPControl.GetContextWeb(Context);
    ListItemCounter listCounter = new ListItemCounter(web);

    try
    {
        output.Write("<div>{0}<b>{1}</b></div>", Message, listCounter.CountListItems(List,Query));
    }
    catch (Exception ex)
    {
        output.Write(String.Format("<div>{0}: {1}</div>", ex.GetType(), ex.Message));
    }
}

...

internal class ListItemCounter
{
    private readonly SPWeb _web;

    public ListItemCounter(SPWeb web)
    {
        _web = web;
    }

    public int CountListItems(string listName, string queryFiler)
    {
        SPList list = _web.Lists[listName];
        SPQuery query = new SPQuery();
        query.Query = queryFiler;
        SPListItemCollection items = list.GetItems(query);

        return items.Count;
    }
}

Esto es importante ya que de este modo nuestro código quedará aislado de algunos de los elementos que el componente Webpart lleva implícitos, como el contexto en el cual la aplicación ASP.Net se está ejecutando; que entre otras cosas da bastante guerra ya que es complicado de reproducir. Y como consecuencia será más sencillo poder realizar las pruebas como veremos.

Monday, September 03, 2007 10:34:15 PM (Hora de verano romance, UTC+02:00)   #    Comments [0]   NET Development | SharePoint-es  | 

Estos días mi querido amigo Gustavo, ha estado pasando un infierno tratando de mejorar el proceso de realizar pruebas unitarias con SharePoint.

Desde mi punto de vista las pruebas con objetos Mock funcionan (luego veremos cómo), pero creo que no siempre son lo más adecuado y esto hay que tenerlo muy en cuenta.

Cuando desarrollamos pruebas unitarias tratamos de ver si existen diferencias entre el comportamiento esperado y el comportamiento observado. Cuando la realización de estas pruebas se convirtió en algo complejo, por la dependencia de nuestro código con sistemas externos surgieron distintas técnicas que nos permiten substituir estos sistemas e independizar nuestras pruebas.

Con estas técnicas, entre las cuales están los objetos Mock, el código que escribimos para realizar la prueba, interactúa con impostores, falsificaciones, espías, objetos simulados etc... Es decir con fantasmas.

Fantasmas, “ectoplasmas” que aparentan ser lo que no son; objetos de verdad. Pero que nos permiten entre otras cosas que nuestra prueba no se detenga por depender de un subsistema externo y muchas veces ajeno a nosotros.

De modo que en la mayoría de los casos, estamos dando por sentado como se comportará ese subsistema, comportamiento esperado. Al predeterminar esto estamos dando por hecho que dicho subsistema funcionará correctamente ó incorrectamente si queremos comprobar que nuestro código sabe responder a las fallas del subsistema, con lo que el subsistema real queda fuera del ámbito de nuestra prueba. Resumiendo, independizamos nuestras pruebas.

Veamos ahora un ejemplo conocido:

public static class Tools
{
    public static string GetCurrentUserName(HttpContext myContext)
    {
        SPWeb myWeb = SPControl.GetContextWeb(myContext);
        SPUser myUser = myWeb.CurrentUser;
        return myUser.LoginName;
    }               
}

Si, es enrevesado ya que estamos usando el contexto de la aplicación web (cosa que deberíamos evitar siempre que podamos, pero eso es otra historia)

Volviendo al código si lo que estamos haciendo es una aplicación ASP.Net que debe interactuar con SharePoint (el subsistema) y queremos realizar una prueba unitaria de este código podemos hacerlo usando objetos Mock.

De este modo nuestra prueba funcionará correctamente sin la necesidad de disponer de una instalación de SharePoint.

Yo personalmente uso TypeMock, que me parece sin lugar a dudas el más completo y con el que menos cuesta (en términos de líneas) realizar los test.

Ejemplo

[Test]
public void GetCurrentUserNameTest()
{
    string expectedUserName = "Sample User";

    MockManager.Init();

    // Hacemos un Mock de SPUser
    // Usando MockManager.MockObject nos permitira crear un objeto sin
    // llamar a su constructor para recuperar la instancia inmediatamente
    MockObject mockSPUser = MockManager.MockObject(typeof (SPUser));

    // Fijamos el valor que será devuelto cuando se solicite el valor de la 
    // propiedad LoginName
    mockSPUser.ExpectGet("LoginName", expectedUserName);
    
    // Devolvemos la instancia para poder usarla
    SPUser spUser = mockSPUser.Object as SPUser;

    // Hacemos un Mock de SPWeb
    MockObject mockSPWeb = MockManager.MockObject(typeof (SPWeb));
    
    // Fijamos el valor que será devuelto cuando se solicite el valor de la
    // propiedad CurrentUser que es el objeto SPUser que creamos anteriormente            
    mockSPWeb.ExpectGet("CurrentUser", spUser);

    // Devolvemos la instancia para poder usarla
    SPWeb spWeb = mockSPWeb.Object as SPWeb;

    // Hacemos un Mock de SPControl
    // En esta ocasion no vamos a instanciarlo ahora, se instanciará automaticamente 
    // cuando se solicite
    Mock mockSPControl = MockManager.Mock(typeof (SPControl));

    // En cualquier caso el método GetContextWeb, devolverá el objeto SPWeb
    mockSPControl.AlwaysReturn("GetContextWeb", spWeb);

    // Tomamos el nombre del usuario
    // Incluso podemos pasarle null (este no es el test de parametros/excepciones)
    string userName = Tools.GetCurrentUserName(null);

    // Comprobamos que el valor esperado es el valor que hemos obtenido
    Assert.AreEqual(expectedUserName, userName, "Correct!!!");

    // Verificamos la prueba
    MockManager.Verify();
}

El código de la prueba nos permite verificar que el método GetCurrentUserName funciona correctamente. Es más no necesitamos depender de SharePoint para probar nuestro código. Ya somos independientes del Subsistema.

Pero si analizamos la prueba, lo único que hemos hecho es prefijar el comportamiento de cada uno de los objetos que usa nuestro método, que como dice un gran amigo, es como decirle al ordenador: Cuándo te pregunte como me llamo, di que me llamo PEPE, y preguntarle ¿Cómo me llamo? a lo cual responderá PEPE, y diremos BIEN, aunque yo me llame JUAN.

Pero eso sí, el maremágnum de pruebas correrá feliz por los mundos de yupi.

Otro tema a tener en cuenta, es, si es necesaria la prueba y cuando debemos realizar este tipo de pruebas ¿Qué estamos probando aquí?, no estamos haciendo un test de excepciones, ni un test de carga, ni un test de delegación etc., ni siquiera una prueba de integración, lo único que estamos haciendo es comprobar que el subsistema de SharePoint, responderá como nosotros esperamos que lo haga. (Cosa que los programadores de SharePoint hacemos habitualmente) De modo que garantizar que SharePoint funciona correctamente no es nuestra tarea. Para nosotros lo importante es el hecho de que interactuamos con un sistema externo y el ámbito de nuestras pruebas debería ser nuestro propio código.

Puede parecer complicado pero yo creo que hay que poner límites a las pruebas, de modo que probaría a ver si estoy controlando todas las excepciones que debería, a la hora de tratar con el subsistema y a asegurarme que los datos que le estoy pasando o que estoy recibiendo de él son los correctos.

Por otro lado cuando desarrollamos en el interior del subsistema (WebParts, Eventos, Workflows, etc.) las cosas pueden cambiar...

Wednesday, August 29, 2007 3:44:01 PM (Hora de verano romance, UTC+02:00)   #    Comments [0]   NET Development | SharePoint-es  | 

En Desarrolla con MSDN han publicado el Curso de Programación para SharePoint 2007 que a realizado Gustavo, sin duda un buen punto para comenzar. El curso es muy completo y además incluye videos.

  1.1 Introducción a WSS y MOSS
  1.2 Instalación de MOSS
  1.3 Construcción de un sitio web basico
  2.1 Integracion con ASP.NET 2.0
  2.2 Modelo de Objetos
  2.3 Paginas Maestras
  2.4 WebParts
  3.1 Que son Tipos de Contenido de Sitios
  3.2 Desarrollo de Tipos de Contenido
  3.3 Que son Columnas de Sitio
  4.1 Introduccion a Caracteristicas
  4.2 Uso de Caracteristicas
  4.3 Estructura XML
  4.4 Desarrollo de Caracteristicas
  5.1 Introduccion a Flujos de Trabajo
  5.2 Uso de Flujos de Trabajo
  5.3 Creacion de Flujos de Trabajo
  5.4 Flujos de Trabajo con SharePoint Designer
  6.1 Introduccion al Catalogo de Datos Profesionales
  6.2 Uso y Creacion del Catalogo de Datos Profesionales
  6.3 Programacion del Catalogo de Datos Profesionales
  7.1 Introduccion al Servicio de Excel
  7.2 Uso del Servicio de Excel
  7.3 Programacion con el Servicio de Excel

También os recuerdo que Gustavo, mantiene un PORTAL donde podéis encontrar cantidad de información sobre programación en SharePoint.

No pierdas el tiempo corre a verlo ...

Friday, August 24, 2007 3:15:31 PM (Hora de verano romance, UTC+02:00)   #    Comments [0]   SharePoint-es  | 

Page 1 of 10 in the SharePoint-es category Next Page

Copyright © 2008 Carlos Segura. All rights reserved.